chore: merge

This commit is contained in:
David Welch 2022-04-29 14:06:13 -06:00
commit ec1f7309f3
88 changed files with 33612 additions and 35026 deletions

View File

@ -11,7 +11,7 @@
flow flow
[options] [options]
unsafe.enable_getters_and_setters=true # unsafe.enable_getters_and_setters=true
module.name_mapper='^compiler/\(.*\)$' -> '<PROJECT_ROOT>/src/compiler/\1' module.name_mapper='^compiler/\(.*\)$' -> '<PROJECT_ROOT>/src/compiler/\1'
module.name_mapper='^core/\(.*\)$' -> '<PROJECT_ROOT>/src/core/\1' module.name_mapper='^core/\(.*\)$' -> '<PROJECT_ROOT>/src/core/\1'
module.name_mapper='^shared/\(.*\)$' -> '<PROJECT_ROOT>/src/shared/\1' module.name_mapper='^shared/\(.*\)$' -> '<PROJECT_ROOT>/src/shared/\1'
@ -20,4 +20,4 @@ module.name_mapper='^weex/\(.*\)$' -> '<PROJECT_ROOT>/src/platforms/weex/\1'
module.name_mapper='^server/\(.*\)$' -> '<PROJECT_ROOT>/src/server/\1' module.name_mapper='^server/\(.*\)$' -> '<PROJECT_ROOT>/src/server/\1'
module.name_mapper='^entries/\(.*\)$' -> '<PROJECT_ROOT>/src/entries/\1' module.name_mapper='^entries/\(.*\)$' -> '<PROJECT_ROOT>/src/entries/\1'
module.name_mapper='^sfc/\(.*\)$' -> '<PROJECT_ROOT>/src/sfc/\1' module.name_mapper='^sfc/\(.*\)$' -> '<PROJECT_ROOT>/src/sfc/\1'
suppress_comment= \\(.\\|\n\\)*\\$flow-disable-line # suppress_comment= \\(.\\|\n\\)*\\$flow-disable-line

View File

@ -124,15 +124,7 @@ The default test script will do the following: lint with ESLint -> type check wi
## Financial Contribution ## Financial Contribution
As a pure community-driven project without major corporate backing, we also welcome financial contributions via Patreon and OpenCollective. 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.
- [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.
## Credits ## Credits

View File

@ -1,488 +1,9 @@
<h1 align="center">Sponsors &amp; Backers</h1> <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: 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/).
- [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-->
<p align="center"> <p align="center">
<a href="https://autocode.com/" target="_blank"> <a target="_blank" href="https://sponsors.vuejs.org/backers.svg">
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true"> <img alt="sponsors" src="https://sponsors.vuejs.org/backers.svg">
</a> </a>
</p> </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/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://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> <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> </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). ## Sponsors
- [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)
#### What's the difference between Patreon and OpenCollective? 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/).
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-->
<p align="center"> <p align="center">
<a href="https://autocode.com/" target="_blank"> <a target="_blank" href="https://vuejs.org/sponsor/">
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true"> <img alt="sponsors" src="https://sponsors.vuejs.org/sponsors.svg">
</a> </a>
</p> </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 ## Ecosystem
| Project | Status | Description | | Project | Status | Description |
|---------|--------|-------------| | --------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing | | [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing |
| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management | | [vuex] | [![vuex-status]][vuex-package] | Large-scale state management |
| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding | | [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-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-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-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-rx] | [![vue-rx-status]][vue-rx-package] | RxJS integration |
| [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension | | [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension |
[vue-router]: https://github.com/vuejs/vue-router [vue-router]: https://github.com/vuejs/vue-router
[vuex]: https://github.com/vuejs/vuex [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-server-renderer]: https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer
[vue-class-component]: https://github.com/vuejs/vue-class-component [vue-class-component]: https://github.com/vuejs/vue-class-component
[vue-rx]: https://github.com/vuejs/vue-rx [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 [vue-router-status]: https://img.shields.io/npm/v/vue-router.svg
[vuex-status]: https://img.shields.io/npm/v/vuex.svg [vuex-status]: https://img.shields.io/npm/v/vuex.svg
[vue-cli-status]: https://img.shields.io/npm/v/@vue/cli.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-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-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-devtools-status]: https://img.shields.io/chrome-web-store/v/nhdogjmejiglipccpnnnanhbledajbpd.svg
[vue-router-package]: https://npmjs.com/package/vue-router [vue-router-package]: https://npmjs.com/package/vue-router
[vuex-package]: https://npmjs.com/package/vuex [vuex-package]: https://npmjs.com/package/vuex
[vue-cli-package]: https://npmjs.com/package/@vue/cli [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> <a href="https://github.com/vuejs/vue/graphs/contributors"><img src="https://opencollective.com/vuejs/contributors.svg?width=890" /></a>
## License ## License
[MIT](https://opensource.org/licenses/MIT) [MIT](https://opensource.org/licenses/MIT)

4894
dist/vue.common.dev.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

4931
dist/vue.esm.js vendored

File diff suppressed because it is too large Load Diff

4906
dist/vue.js vendored

File diff suppressed because it is too large Load Diff

10
dist/vue.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

3231
dist/vue.runtime.esm.js vendored

File diff suppressed because it is too large Load Diff

3201
dist/vue.runtime.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,164 +0,0 @@
{
"name": "vue",
"version": "2.6.12",
"description": "Reactive, component-oriented view layer for modern web interfaces.",
"main": "dist/vue.runtime.common.js",
"module": "dist/vue.runtime.esm.js",
"unpkg": "dist/vue.js",
"jsdelivr": "dist/vue.js",
"typings": "types/index.d.ts",
"files": [
"src",
"dist/*.js",
"types/*.d.ts"
],
"sideEffects": false,
"scripts": {
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
"dev:cjs": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-cjs-dev",
"dev:esm": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-esm",
"dev:test": "karma start test/unit/karma.dev.config.js",
"dev:ssr": "rollup -w -c scripts/config.js --environment TARGET:web-server-renderer",
"dev:compiler": "rollup -w -c scripts/config.js --environment TARGET:web-compiler ",
"dev:weex": "rollup -w -c scripts/config.js --environment TARGET:weex-framework",
"dev:weex:factory": "rollup -w -c scripts/config.js --environment TARGET:weex-factory",
"dev:weex:compiler": "rollup -w -c scripts/config.js --environment TARGET:weex-compiler ",
"build": "node scripts/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex": "npm run build -- weex",
"test": "npm run lint && flow check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr && npm run test:weex",
"test:unit": "karma start test/unit/karma.unit.config.js",
"test:cover": "karma start test/unit/karma.cover.config.js",
"test:e2e": "npm run build -- web-full-prod,web-server-basic-renderer && node test/e2e/runner.js",
"test:weex": "npm run build:weex && jasmine-ts JASMINE_CONFIG_PATH=test/weex/jasmine.js",
"test:ssr": "npm run build:ssr && jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.js",
"test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2",
"test:types": "tsc -p ./types/test/tsconfig.json",
"lint": "eslint src scripts test",
"flow": "flow check",
"ts-check": "tsc --noEmit",
"sauce": "karma start test/unit/karma.sauce.config.js",
"bench:ssr": "npm run build:ssr && node benchmarks/ssr/renderToString.js && node benchmarks/ssr/renderToStream.js",
"release": "bash scripts/release.sh",
"release:weex": "bash scripts/release-weex.sh",
"release:note": "node scripts/gen-release-note.js",
"commit": "git-cz"
},
"gitHooks": {
"pre-commit": "lint-staged",
"commit-msg": "node scripts/verify-commit-msg.js"
},
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vue.git"
},
"keywords": [
"vue"
],
"author": "Evan You",
"license": "MIT",
"bugs": {
"url": "https://github.com/vuejs/vue/issues"
},
"homepage": "https://github.com/vuejs/vue#readme",
"devDependencies": {
"@babel/core": "^7.13.14",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.12.13",
"@babel/plugin-transform-flow-strip-types": "^7.13.0",
"@babel/preset-env": "^7.13.12",
"@babel/register": "^7.13.14",
"@mapbox/node-pre-gyp": "1.0.9",
"@rollup/plugin-alias": "^3.1.2",
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-commonjs": "^18.0.0",
"@rollup/plugin-node-resolve": "^11.2.1",
"@rollup/plugin-replace": "^2.4.2",
"@types/node": "^12.12.0",
"@types/webpack": "^4.4.22",
"@typescript-eslint/eslint-plugin": "^4.21.0",
"@typescript-eslint/parser": "^4.21.0",
"acorn": "^8.1.0",
"acorn-walk": "^8.0.2",
"babel-eslint": "^10.0.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^8.0.4",
"babel-plugin-istanbul": "^5.1.0",
"babel-plugin-transform-vue-jsx": "^4.0.1",
"babel-preset-flow-vue": "^1.0.0",
"buble": "^0.20.0",
"chalk": "^2.3.0",
"chokidar": "^3.5.3",
"chromedriver": "^90.0",
"codecov": "^3.0.0",
"commitizen": "^2.9.6",
"conventional-changelog": "^1.1.3",
"cross-spawn": "^6.0.5",
"cz-conventional-changelog": "^2.0.0",
"de-indent": "^1.0.2",
"es6-promise": "^4.1.0",
"escodegen": "^1.8.1",
"eslint": "^7.23.0",
"eslint-plugin-flowtype": "^2.34.0",
"eslint-plugin-jasmine": "^2.8.4",
"file-loader": "^3.0.1",
"flow-bin": "^0.61.0",
"fsevents": "2.3.2",
"hash-sum": "^1.0.2",
"he": "^1.1.1",
"http-server": "^0.12.3",
"jasmine": "^2.99.0",
"jasmine-core": "^2.99.0",
"jasmine-ts": "^0.3.2",
"karma": "^3.1.1",
"karma-chrome-launcher": "^2.1.1",
"karma-coverage": "^1.1.1",
"karma-firefox-launcher": "^1.0.1",
"karma-jasmine": "^1.1.0",
"karma-mocha-reporter": "^2.2.3",
"karma-phantomjs-launcher": "^1.0.4",
"karma-safari-launcher": "^1.0.0",
"karma-sauce-launcher": "^2.0.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.0-rc.2",
"lint-staged": "^8.0.0",
"lodash": "^4.17.4",
"lodash.template": "^4.4.0",
"lodash.uniq": "^4.5.0",
"lru-cache": "^5.1.1",
"nightwatch": "^0.9.16",
"nightwatch-helpers": "^1.2.0",
"phantomjs-prebuilt": "^2.1.14",
"puppeteer": "^1.11.0",
"resolve": "^1.3.3",
"rollup": "^2.44.0",
"rollup-plugin-typescript2": "^0.30.0",
"selenium-server": "^2.53.1",
"serialize-javascript": "^3.1.0",
"shelljs": "^0.8.1",
"terser": "^5.6.1",
"ts-loader": "^8.1.0",
"ts-node": "^9.1.1",
"tslib": "^2.2.0",
"typescript": "^4.2.2",
"webpack": "~4.28.4",
"weex-js-runtime": "^0.23.6",
"weex-styler": "^0.3.0",
"yorkie": "^2.0.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"dependencies": {
"@types/he": "^1.1.1"
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@ -1,28 +1,49 @@
'use strict'; 'use strict';
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); }; const isJS = (file) => /\.js(\?[^.]+)?$/.test(file);
var ref = require('chalk'); const { red, yellow } = require('chalk');
var red = ref.red; const webpack = require('webpack');
var yellow = ref.yellow; const prefix = `[vue-server-renderer-webpack-plugin]`;
var prefix = "[vue-server-renderer-webpack-plugin]"; const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`));
var warn = (exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); }); const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`));
var tip = (exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); }); const isWebpack5 = !!(webpack.version && webpack.version[0] > 4);
var validate = function (compiler) { const validate = compiler => {
if (compiler.options.target !== 'node') { if (compiler.options.target !== 'node') {
warn('webpack config `target` should be "node".'); warn('webpack config `target` should be "node".');
} }
if (compiler.options.output && if (compiler.options.output) {
compiler.options.output.libraryTarget !== 'commonjs2') { if (compiler.options.output.library) {
warn('webpack config `output.libraryTarget` should be "commonjs2".'); // 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) { if (!compiler.options.externals) {
tip('It is recommended to externalize dependencies in the server build for ' + tip('It is recommended to externalize dependencies in the server build for ' +
'better build performance.'); 'better build performance.');
} }
}; };
var onEmit = function (compiler, name, hook) { const onEmit = (compiler, name, stageName, hook) => {
if (compiler.hooks) { 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 // Webpack >= 4.0.0
compiler.hooks.emit.tapAsync(name, hook); compiler.hooks.emit.tapAsync(name, hook);
} }
@ -31,60 +52,67 @@ var onEmit = function (compiler, name, hook) {
compiler.plugin('emit', hook); compiler.plugin('emit', hook);
} }
}; };
const getAssetName = asset => {
var VueSSRServerPlugin = function VueSSRServerPlugin(options) { if (typeof asset === 'string') {
if ( options === void 0 ) options = {}; return asset;
}
//@ts-expect-error return asset.name;
this.options = Object.assign({
filename: 'vue-ssr-server-bundle.json',
}, options);
}; };
VueSSRServerPlugin.prototype.apply = function apply (compiler) {
var this$1 = this;
validate(compiler); class VueSSRServerPlugin {
onEmit(compiler, 'vue-server-plugin', function (compilation, cb) { constructor(options = {}) {
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 //@ts-expect-error
var filename = this$1.options.filename; this.options = Object.assign({
compilation.assets[filename] = { filename: 'vue-ssr-server-bundle.json',
source: function () { return json; }, }, options);
size: function () { return json.length; }, }
}; apply(compiler) {
cb(); validate(compiler);
}); 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];
if (!entryInfo) {
// #5553
return cb();
}
const 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.`);
}
const entry = entryAssets[0];
if (!entry || typeof entry !== 'string') {
throw new Error(`Entry "${entryName}" not found. Did you specify the correct entry option?`);
}
const bundle = {
entry,
files: {},
maps: {},
};
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[name];
});
const json = JSON.stringify(bundle, null, 2);
//@ts-expect-error
const filename = this.options.filename;
compilation.assets[filename] = {
source: () => json,
size: () => json.length,
};
cb();
});
}
}
module.exports = VueSSRServerPlugin; module.exports = VueSSRServerPlugin;

View File

@ -1,9 +1,11 @@
import { Plugin } from 'webpack'; import { DefinePlugin } from 'webpack';
interface WebpackPluginOptions { interface WebpackPluginOptions {
filename?: string; filename?: string;
} }
export interface WebpackPlugin { export interface WebpackPlugin {
new (options?: WebpackPluginOptions): Plugin; // NOTE NOT SURE ABOUT THIS
// TODO DOUBLE CHECK HERE
new (options?: WebpackPluginOptions): DefinePlugin;
} }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -267,9 +267,9 @@ function genConfig (name) {
vars.preventAssignment = true vars.preventAssignment = true
config.plugins.push(replace(vars)) config.plugins.push(replace(vars))
if (opts.transpile !== false) { // if (opts.transpile !== false) {
config.plugins.push(buble()) // config.plugins.push(buble())
} // }
Object.defineProperty(config, '_name', { Object.defineProperty(config, '_name', {
enumerable: false, enumerable: false,

View File

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

View File

@ -103,7 +103,7 @@ function checkIdentifier(
if (typeof ident === 'string') { if (typeof ident === 'string') {
try { try {
new Function(`var ${ident}=_`) new Function(`var ${ident}=_`)
} catch (e) { } catch (e: any) {
warn(`invalid ${type} "${ident}" in expression: ${text.trim()}`, range) warn(`invalid ${type} "${ident}" in expression: ${text.trim()}`, range)
} }
} }
@ -117,7 +117,7 @@ function checkExpression(
) { ) {
try { try {
new Function(`return ${exp}`) new Function(`return ${exp}`)
} catch (e) { } catch (e:any) {
const keywordMatch = exp const keywordMatch = exp
.replace(stripStringRE, '') .replace(stripStringRE, '')
.match(prohibitedKeywordRE) .match(prohibitedKeywordRE)
@ -146,7 +146,7 @@ function checkFunctionParameterExpression(
) { ) {
try { try {
new Function(exp, '') new Function(exp, '')
} catch (e) { } catch (e:any) {
warn( warn(
`invalid function parameter expression: ${e.message} in\n\n` + `invalid function parameter expression: ${e.message} in\n\n` +
` ${exp}\n\n` + ` ${exp}\n\n` +

View File

@ -12,7 +12,7 @@ type CompiledFunctionResult = {
function createFunction(code, errors) { function createFunction(code, errors) {
try { try {
return new Function(code) return new Function(code)
} catch (err) { } catch (err: any) {
errors.push({ err, code }) errors.push({ err, code })
return noop return noop
} }
@ -35,7 +35,7 @@ export function createCompileToFunctionFn(compile: Function): Function {
// detect possible CSP restriction // detect possible CSP restriction
try { try {
new Function('return 1') new Function('return 1')
} catch (e) { } catch (e:any) {
if (e.toString().match(/unsafe-eval|CSP/)) { if (e.toString().match(/unsafe-eval|CSP/)) {
warn( warn(
'It seems you are using the standalone build of Vue.js in an ' + 'It seems you are using the standalone build of Vue.js in an ' +

View File

@ -1,12 +1,21 @@
import { isRegExp, remove } from 'shared/util' /* @flow */
import { getFirstComponentChild } from 'core/vdom/helpers/index'
import VNode from 'core/vdom/vnode'
import type { VNodeComponentOptions } from 'typescript/vnode'
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 { function getComponentName(opts?: VNodeComponentOptions): string | null {
return opts && (opts.Ctor.options.name || opts.tag) return opts && (opts.Ctor.options.name || opts.tag);
} }
function matches( function matches(
@ -14,49 +23,52 @@ function matches(
name: string name: string
): boolean { ): boolean {
if (Array.isArray(pattern)) { if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1 return pattern.indexOf(name) > -1;
} else if (typeof pattern === 'string') { } else if (typeof pattern === "string") {
return pattern.split(',').indexOf(name) > -1 return pattern.split(",").indexOf(name) > -1;
} else if (isRegExp(pattern)) { } else if (isRegExp(pattern)) {
return pattern.test(name) return pattern.test(name);
} }
/* istanbul ignore next */ /* istanbul ignore next */
return false return false;
} }
function pruneCache(keepAliveInstance: any, filter: Function) { function pruneCache(
const { cache, keys, _vnode } = keepAliveInstance keepAliveInstance: { cache: CacheEntryMap; keys: string[]; _vnode: VNode },
filter: Function
) {
const { cache, keys, _vnode } = keepAliveInstance;
for (const key in cache) { for (const key in cache) {
const cachedNode: VNode | null = cache[key] const entry = cache[key];
if (cachedNode) { if (entry) {
const name = getComponentName(cachedNode.componentOptions) const name = entry.name;
if (name && !filter(name)) { if (name && !filter(name)) {
pruneCacheEntry(cache, key, keys, _vnode) pruneCacheEntry(cache, key, keys, _vnode);
} }
} }
} }
} }
function pruneCacheEntry( function pruneCacheEntry(
cache: VNodeCache, cache: CacheEntryMap,
key: string, key: string,
keys: Array<string>, keys: Array<string>,
current?: VNode current?: VNode
) { ) {
const cached = cache[key] const entry = cache[key];
if (cached && (!current || cached.tag !== current.tag)) { if (entry && (!current || entry.tag !== current.tag)) {
//@ts-expect-error has void type // @ts-expect-error can be undefined
cached.componentInstance.$destroy() entry.componentInstance.$destroy();
} }
cache[key] = null cache[key] = null;
remove(keys, key) remove(keys, key);
} }
const patternTypes: Array<Function> = [String, RegExp, Array] const patternTypes: Array<Function> = [String, RegExp, Array];
// TODO use defineComponent // TODO defineComponent
export default { export default {
name: 'keep-alive', name: "keep-alive",
abstract: true, abstract: true,
props: { props: {
@ -65,68 +77,90 @@ export default {
max: [String, Number], 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() { created() {
this.cache = Object.create(null) this.cache = Object.create(null);
this.keys = [] this.keys = [];
}, },
destroyed() { destroyed() {
for (const key in this.cache) { for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys) pruneCacheEntry(this.cache, key, this.keys);
} }
}, },
mounted() { mounted() {
this.$watch('include', (val) => { this.cacheVNode();
pruneCache(this, (name) => matches(val, name)) this.$watch("include", (val) => {
}) pruneCache(this, (name) => matches(val, name));
this.$watch('exclude', (val) => { });
pruneCache(this, (name) => !matches(val, name)) this.$watch("exclude", (val) => {
}) pruneCache(this, (name) => !matches(val, name));
});
},
updated() {
this.cacheVNode();
}, },
render() { render() {
const slot = this.$slots.default const slot = this.$slots.default;
const vnode = getFirstComponentChild(slot) const vnode = getFirstComponentChild(slot);
const componentOptions = const componentOptions = vnode && vnode.componentOptions;
vnode && vnode.componentOptions
if (componentOptions) { if (componentOptions) {
// check pattern // check pattern
const name = getComponentName(componentOptions) const name = getComponentName(componentOptions);
const { include, exclude } = this const { include, exclude } = this;
if ( if (
// not included // not included
(include && (!name || !matches(include, name))) || (include && (!name || !matches(include, name))) ||
// excluded // excluded
(exclude && name && matches(exclude, name)) (exclude && name && matches(exclude, name))
) { ) {
return vnode return vnode;
} }
const { cache, keys } = this const { cache, keys } = this;
const key = const key =
vnode!.key == null vnode.key == null
? // same constructor may get registered as different local components ? // same constructor may get registered as different local components
// so cid alone is not enough (#3269) // so cid alone is not enough (#3269)
componentOptions.Ctor.cid + componentOptions.Ctor.cid +
(componentOptions.tag ? `::${componentOptions.tag}` : '') (componentOptions.tag ? `::${componentOptions.tag}` : "")
: vnode!.key : vnode.key;
if (cache[key]) { if (cache[key]) {
vnode!.componentInstance = cache[key].componentInstance vnode.componentInstance = cache[key].componentInstance;
// make current key freshest // make current key freshest
remove(keys, key) remove(keys, key);
keys.push(key) keys.push(key);
} else { } else {
cache[key] = vnode // delay setting the cache until update
keys.push(key) this.vnodeToCache = vnode;
// prune oldest entry this.keyToCache = key;
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
} }
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 { resolveSlots } from "./render-helpers/resolve-slots";
import { toggleObserving } from "../observer/index"; import { toggleObserving } from "../observer/index";
import { pushTarget, popTarget } from "../observer/dep"; import { pushTarget, popTarget } from "../observer/dep";
import type { Component } from "../../../typescript/component";
import type { MountedComponentVNode } from "../../../typescript/vnode";
import { import {
warn, warn,
@ -15,8 +17,6 @@ import {
validateProp, validateProp,
invokeWithErrorHandling, invokeWithErrorHandling,
} from "../util/index"; } from "../util/index";
import type { Component } from "typescript/component";
import type { MountedComponentVNode } from "typescript/vnode";
export let activeInstance: any = null; export let activeInstance: any = null;
export let isUpdatingChildComponent: boolean = false; export let isUpdatingChildComponent: boolean = false;
@ -30,7 +30,7 @@ export function setActiveInstance(vm: Component) {
} }
export function initLifecycle(vm: Component) { export function initLifecycle(vm: Component) {
const options: any = vm.$options; const options = vm.$options;
// locate first non-abstract parent // locate first non-abstract parent
let parent = options.parent; let parent = options.parent;
@ -122,7 +122,7 @@ export function lifecycleMixin(Vue: Component) {
// call the last hook... // call the last hook...
vm._isDestroyed = true; vm._isDestroyed = true;
// invoke destroy hooks on current rendered tree // invoke destroy hooks on current rendered tree
vm.__patch__(vm._vnode!, null); vm.__patch__(vm._vnode, null);
// fire destroyed hook // fire destroyed hook
callHook(vm, "destroyed"); callHook(vm, "destroyed");
// turn off all instance listeners. // turn off all instance listeners.
@ -133,7 +133,6 @@ export function lifecycleMixin(Vue: Component) {
} }
// release circular reference (#6759) // release circular reference (#6759)
if (vm.$vnode) { if (vm.$vnode) {
// @ts-expect-error null is not undefined
vm.$vnode.parent = null; vm.$vnode.parent = null;
} }
}; };
@ -240,12 +239,13 @@ export function updateChildComponent(
// check if there are dynamic scopedSlots (hand-written or compiled but with // check if there are dynamic scopedSlots (hand-written or compiled but with
// dynamic slot names). Static scoped slots compiled from template has the // dynamic slot names). Static scoped slots compiled from template has the
// "$stable" marker. // "$stable" marker.
const newScopedSlots = parentVnode!.data.scopedSlots; const newScopedSlots = parentVnode.data.scopedSlots;
const oldScopedSlots = vm.$scopedSlots; const oldScopedSlots = vm.$scopedSlots;
const hasDynamicScopedSlot = !!( const hasDynamicScopedSlot = !!(
(newScopedSlots && !newScopedSlots.$stable) || (newScopedSlots && !newScopedSlots.$stable) ||
(oldScopedSlots !== emptyObject && !oldScopedSlots.$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 // 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.$options._parentVnode = parentVnode;
vm.$vnode = parentVnode; // update vm's placeholder node without re-render vm.$vnode = parentVnode; // update vm's placeholder node without re-render
if (vm._vnode) { if (vm._vnode) {
@ -270,7 +269,7 @@ export function updateChildComponent(
// update $attrs and $listeners hash // update $attrs and $listeners hash
// these are also reactive so they may trigger child update if the child // these are also reactive so they may trigger child update if the child
// used them during render // used them during render
vm.$attrs = parentVnode!.data.attrs || emptyObject; vm.$attrs = parentVnode.data.attrs || emptyObject;
vm.$listeners = listeners || emptyObject; vm.$listeners = listeners || emptyObject;
// update props // update props
@ -296,7 +295,7 @@ export function updateChildComponent(
// resolve slots + force update if has children // resolve slots + force update if has children
if (needsForceUpdate) { if (needsForceUpdate) {
vm.$slots = resolveSlots(renderChildren, parentVnode!.context); vm.$slots = resolveSlots(renderChildren, parentVnode.context);
vm.$forceUpdate(); vm.$forceUpdate();
} }

View File

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

View File

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

View File

@ -115,7 +115,7 @@ export function renderMixin(Vue: Component) {
// when parent component is patched. // when parent component is patched.
currentRenderingInstance = vm currentRenderingInstance = vm
vnode = render.call(vm._renderProxy, vm.$createElement) vnode = render.call(vm._renderProxy, vm.$createElement)
} catch (e) { } catch (e: any) {
handleError(e, vm, `render`) handleError(e, vm, `render`)
// return error render result, // return error render result,
// or previous vnode to prevent render error causing blank component // or previous vnode to prevent render error causing blank component
@ -127,7 +127,7 @@ export function renderMixin(Vue: Component) {
vm.$createElement, vm.$createElement,
e e
) )
} catch (e) { } catch (e:any) {
handleError(e, vm, `renderError`) handleError(e, vm, `renderError`)
vnode = vm._vnode vnode = vm._vnode
} }

View File

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

View File

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

View File

@ -33,7 +33,7 @@ if (inBrowser) {
}, },
} as object) // https://github.com/facebook/flow/issues/285 } as object) // https://github.com/facebook/flow/issues/285
window.addEventListener('test-passive', null as any, opts) window.addEventListener('test-passive', null as any, opts)
} catch (e) {} } catch (e: any) {}
} }
// this needs to be lazy-evaled because vue may be required before // this needs to be lazy-evaled because vue may be required before
@ -75,10 +75,8 @@ let _Set // $flow-disable-line
} else { } else {
// a non-standard Set polyfill that only works with primitive keys. // a non-standard Set polyfill that only works with primitive keys.
_Set = class Set implements SimpleSet { _Set = class Set implements SimpleSet {
set: Object set: Record<string, boolean> = Object.create(null)
constructor() {
this.set = Object.create(null)
}
has(key: string | number) { has(key: string | number) {
return this.set[key] === true return this.set[key] === true
} }

View File

@ -18,7 +18,7 @@ export function handleError(err: Error, vm: any, info: string) {
try { try {
const capture = hooks[i].call(cur, err, vm, info) === false const capture = hooks[i].call(cur, err, vm, info) === false
if (capture) return if (capture) return
} catch (e) { } catch (e: any) {
globalHandleError(e, cur, 'errorCaptured hook') globalHandleError(e, cur, 'errorCaptured hook')
} }
} }
@ -47,7 +47,7 @@ export function invokeWithErrorHandling(
// avoid catch triggering multiple times when nested calls // avoid catch triggering multiple times when nested calls
res._handled = true res._handled = true
} }
} catch (e) { } catch (e: any) {
handleError(e, vm, info) handleError(e, vm, info)
} }
return res return res
@ -57,7 +57,7 @@ function globalHandleError(err, vm, info) {
if (config.errorHandler) { if (config.errorHandler) {
try { try {
return config.errorHandler.call(null, err, vm, info) return config.errorHandler.call(null, err, vm, info)
} catch (e) { } catch (e: any) {
// if the user intentionally throws the original error in the handler, // if the user intentionally throws the original error in the handler,
// do not log it twice // do not log it twice
if (e !== err) { if (e !== err) {

View File

@ -91,7 +91,8 @@ export function nextTick(cb?: Function, ctx?: Object) {
if (cb) { if (cb) {
try { try {
cb.call(ctx) cb.call(ctx)
} catch (e) { } catch (e: any) {
// @ts-expect-error should it be any?
handleError(e, ctx, 'nextTick') handleError(e, ctx, 'nextTick')
} }
} else if (_resolve) { } else if (_resolve) {

View File

@ -175,7 +175,7 @@ function assertType(
} else { } else {
try { try {
valid = value instanceof type valid = value instanceof type
} catch (e) { } catch (e: any) {
warn('Invalid prop type: "' + String(type) + '" is not a constructor', vm) warn('Invalid prop type: "' + String(type) + '" is not a constructor', vm)
valid = false valid = false
} }

View File

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

View File

@ -120,7 +120,8 @@ function callHook(dir, hook, vnode, oldVnode, isDestroy?: any) {
if (fn) { if (fn) {
try { try {
fn(vnode.elm, dir, vnode, oldVnode, isDestroy) fn(vnode.elm, dir, vnode, oldVnode, isDestroy)
} catch (e) { } catch (e: any) {
// @ts-expect-error should it be any?
handleError(e, vnode.context, `directive ${dir.name} ${hook} hook`) handleError(e, vnode.context, `directive ${dir.name} ${hook} hook`)
} }
} }

View File

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

View File

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

View File

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

View File

@ -74,7 +74,7 @@ function updateDOMProps(oldVnode: VNodeWithData, vnode: VNodeWithData) {
// e.g. `value` on <progress> w/ non-finite value // e.g. `value` on <progress> w/ non-finite value
try { try {
elm[key] = cur elm[key] = cur
} catch (e) {} } catch (e: any) {}
} }
} }
} }
@ -100,7 +100,7 @@ function isNotInFocusAndDirty(elm: acceptValueElm, checkVal: string): boolean {
// work around IE bug when accessing document.activeElement in an iframe // work around IE bug when accessing document.activeElement in an iframe
try { try {
notInFocus = document.activeElement !== elm notInFocus = document.activeElement !== elm
} catch (e) {} } catch (e: any) {}
return notInFocus && elm.value !== checkVal return notInFocus && elm.value !== checkVal
} }

View File

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

View File

@ -45,7 +45,6 @@ if (hasTransition) {
/* istanbul ignore if */ /* istanbul ignore if */
if ( if (
window.ontransitionend === undefined && window.ontransitionend === undefined &&
// @ts-expect-error
window.onwebkittransitionend !== undefined window.onwebkittransitionend !== undefined
) { ) {
transitionProp = 'WebkitTransition' transitionProp = 'WebkitTransition'
@ -53,7 +52,6 @@ if (hasTransition) {
} }
if ( if (
window.onanimationend === undefined && window.onanimationend === undefined &&
// @ts-expect-error
window.onwebkitanimationend !== undefined window.onwebkitanimationend !== undefined
) { ) {
animationProp = 'WebkitAnimation' animationProp = 'WebkitAnimation'

View File

@ -13,6 +13,7 @@ export function genClassForVnode(vnode: VNodeWithData): string {
data = mergeClassData(childNode.data, data) data = mergeClassData(childNode.data, data)
} }
} }
// @ts-expect-error parentNode.parent not VNodeWithData
while (isDef((parentNode = parentNode.parent))) { while (isDef((parentNode = parentNode.parent))) {
if (parentNode && parentNode.data) { if (parentNode && parentNode.data) {
data = mergeClassData(data, parentNode.data) data = mergeClassData(data, parentNode.data)

View File

@ -62,6 +62,7 @@ export function getStyle(vnode: VNodeWithData, checkChild: boolean): Object {
} }
let parentNode: VNodeWithData | VNode | undefined = vnode let parentNode: VNodeWithData | VNode | undefined = vnode
// @ts-expect-error parentNode.parent not VNodeWithData
while ((parentNode = parentNode.parent)) { while ((parentNode = parentNode.parent)) {
if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) { if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) {
extend(res, styleData) extend(res, styleData)

View File

@ -25,11 +25,11 @@ export function createInstanceContext(
instanceId, instanceId,
config: weex.config, config: weex.config,
document: weex.document, document: weex.document,
data, data
}) })
// Each instance has a independent `Vue` module instance // Each instance has an independent `Vue` module instance
const Vue = (instance.Vue = createVueModuleInstance(instanceId, weex)) const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
// DEPRECATED // DEPRECATED
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule) const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)
@ -50,7 +50,7 @@ export function destroyInstance(instanceId: string): void {
try { try {
instance.app!.$destroy() instance.app!.$destroy()
instance.document.destroy() instance.document.destroy()
} catch (e) {} } catch (e: any) {}
//@ts-expect-error //@ts-expect-error
delete instance.document delete instance.document
delete instance.app delete instance.app
@ -137,7 +137,7 @@ function createVueModuleInstance(instanceId: string, weex: Weex): GlobalAPI {
try { try {
// Send "createFinish" signal to native. // Send "createFinish" signal to native.
weex.document.taskCenter.send('dom', { action: 'createFinish' }, []) weex.document.taskCenter.send('dom', { action: 'createFinish' }, [])
} catch (e) {} } catch (e: any) {}
} }
}, },
}) })

View File

@ -22,7 +22,7 @@ export function renderRecyclableComponentTemplate(
if (render) { if (render) {
try { try {
return render.call(vm) return render.call(vm)
} catch (err) { } catch (err:any) {
handleError(err, vm, `@render`) handleError(err, vm, `@render`)
} }
} else { } else {

View File

@ -44,7 +44,7 @@ export function generateBinding(exp?: string): any {
let ast: acorn.Node| null = null; let ast: acorn.Node| null = null;
try { try {
ast = acorn.parse(`(${exp})`, {ecmaVersion: 5}); ast = acorn.parse(`(${exp})`, {ecmaVersion: 5});
} catch (e) { } catch (e: any) {
// warn(`Failed to parse the expression: "${exp}"`) // warn(`Failed to parse the expression: "${exp}"`)
return ""; return "";
} }

View File

@ -54,7 +54,7 @@ export function createBundleRendererCreator(
try { try {
// @ts-expect-error // @ts-expect-error
bundle = JSON.parse(bundle) bundle = JSON.parse(bundle)
} catch (e) { } catch (e: any) {
throw new Error(`Invalid JSON bundle file: ${bundle}`) throw new Error(`Invalid JSON bundle file: ${bundle}`)
} }
} }

View File

@ -31,7 +31,7 @@ export function createBasicRenderer({
render(component, write, context, () => { render(component, write, context, () => {
done(null, result) done(null, result)
}) })
} catch (e) { } catch (e: any) {
done(e) done(e)
} }
} }

View File

@ -106,14 +106,14 @@ export function createRenderer({
} else { } else {
cb(null, res) cb(null, res)
} }
} catch (e) { } catch (e: any) {
cb(e) cb(e)
} }
} else { } else {
cb(null, result) cb(null, result)
} }
}) })
} catch (e) { } catch (e: any) {
cb(e) cb(e)
} }

View File

@ -64,7 +64,7 @@ export default class RenderStream extends Readable {
tryRender() { tryRender() {
try { try {
this.render(this.write, this.end) this.render(this.write, this.end)
} catch (e) { } catch (e: any) {
this.emit('error', e) this.emit('error', e)
} }
} }
@ -72,7 +72,7 @@ export default class RenderStream extends Readable {
tryNext() { tryNext() {
try { try {
this.next() this.next()
} catch (e) { } catch (e: any) {
this.emit('error', e) this.emit('error', e)
} }
} }

View File

@ -70,7 +70,7 @@ function waitForServerPrefetch(vm, resolve, reject) {
} }
Promise.all(promises).then(resolve).catch(reject) Promise.all(promises).then(resolve).catch(reject)
return return
} catch (e) { } catch (e: any) {
reject(e) reject(e)
} }
} }
@ -264,7 +264,7 @@ function renderAsyncComponent(node, isRoot, context) {
let res let res
try { try {
res = factory(resolve, reject) res = factory(resolve, reject)
} catch (e) { } catch (e: any) {
reject(e) reject(e)
} }
if (res) { if (res) {

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 hash = require("hash-sum");
const uniq = require('lodash.uniq') const uniq = require("lodash.uniq");
import { isJS, isCSS, onEmit } from './util' import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from "./util";
export default class VueSSRClientPlugin { export default class VueSSRClientPlugin {
constructor(options = {}) { constructor(options = {}) {
//@ts-expect-error //@ts-expect-error no type on options
this.options = Object.assign( this.options = Object.assign(
{ {
filename: 'vue-ssr-client-manifest.json', filename: "vue-ssr-client-manifest.json",
}, },
options options
) );
} }
apply(compiler) { apply(compiler) {
onEmit(compiler, 'vue-client-plugin', (compilation, cb) => { const stage = "PROCESS_ASSETS_STAGE_ADDITIONAL";
const stats = compilation.getStats().toJson() 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( const initialFiles = uniq(
Object.keys(stats.entrypoints) Object.keys(stats.entrypoints)
.map((name) => stats.entrypoints[name].assets) .map((name) => stats.entrypoints[name].assets)
.reduce((assets, all) => all.concat(assets), []) .reduce((assets, all) => all.concat(assets), [])
.map(getAssetName)
.filter((file) => isJS(file) || isCSS(file)) .filter((file) => isJS(file) || isCSS(file))
) );
const asyncFiles = allFiles const asyncFiles = allFiles
.filter((file) => isJS(file) || isCSS(file)) .filter((file) => isJS(file) || isCSS(file))
.filter((file) => initialFiles.indexOf(file) < 0) .filter((file) => initialFiles.indexOf(file) < 0);
const manifest = { const manifest = {
publicPath: stats.publicPath, publicPath: stats.publicPath,
@ -38,38 +40,37 @@ export default class VueSSRClientPlugin {
modules: { modules: {
/* [identifier: string]: Array<index: number> */ /* [identifier: string]: Array<index: number> */
}, },
} };
const assetModules = stats.modules.filter((m) => m.assets.length) const assetModules = stats.modules.filter((m) => m.assets.length);
const fileToIndex = (file) => manifest.all.indexOf(file) const fileToIndex = (asset) => manifest.all.indexOf(getAssetName(asset));
stats.modules.forEach((m) => { stats.modules.forEach((m) => {
// ignore modules duplicated in multiple chunks // ignore modules duplicated in multiple chunks
if (m.chunks.length === 1) { if (m.chunks.length === 1) {
const cid = m.chunks[0] const cid = m.chunks[0];
const chunk = stats.chunks.find((c) => c.id === cid) const chunk = stats.chunks.find((c) => c.id === cid);
if (!chunk || !chunk.files) { if (!chunk || !chunk.files) {
return return;
} }
const id = m.identifier.replace(/\s\w+$/, '') // remove appended hash const id = stripModuleIdHash(m.identifier);
const files = (manifest.modules[hash(id)] = chunk.files.map( const files = (manifest.modules[hash(id)] =
fileToIndex chunk.files.map(fileToIndex));
))
// find all asset modules associated with the same chunk // find all asset modules associated with the same chunk
assetModules.forEach((m) => { assetModules.forEach((m) => {
if (m.chunks.some((id) => id === cid)) { 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) const json = JSON.stringify(manifest, null, 2);
//@ts-expect-error //@ts-expect-error no type on options
compilation.assets[this.options.filename] = { compilation.assets[this.options.filename] = {
source: () => json, source: () => json,
size: () => json.length, 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 { export default class VueSSRServerPlugin {
constructor(options = {}) { constructor(options = {}) {
@ -14,7 +14,8 @@ export default class VueSSRServerPlugin {
apply(compiler) { apply(compiler) {
validate(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 stats = compilation.getStats().toJson()
const entryName = Object.keys(stats.entrypoints)[0] const entryName = Object.keys(stats.entrypoints)[0]
const entryInfo = stats.entrypoints[entryName] const entryInfo = stats.entrypoints[entryName]
@ -24,7 +25,9 @@ export default class VueSSRServerPlugin {
return cb() return cb()
} }
const entryAssets = entryInfo.assets.filter(isJS) const entryAssets = entryInfo.assets
.map(getAssetName)
.filter(isJS)
if (entryAssets.length > 1) { if (entryAssets.length > 1) {
throw new Error( throw new Error(
@ -46,16 +49,14 @@ export default class VueSSRServerPlugin {
maps: {}, maps: {},
} }
stats.assets.forEach((asset) => { Object.keys(compilation.assets).forEach(name => {
if (isJS(asset.name)) { if (isJS(name)) {
bundle.files[asset.name] = compilation.assets[asset.name].source() bundle.files[name] = compilation.assets[name].source()
} else if (asset.name.match(/\.js\.map$/)) { } else if (name.match(/\.js\.map$/)) {
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse( bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source())
compilation.assets[asset.name].source()
)
} }
// do not emit anything else for server // do not emit anything else for server
delete compilation.assets[asset.name] delete compilation.assets[name]
}) })
const json = JSON.stringify(bundle, null, 2) const json = JSON.stringify(bundle, null, 2)

View File

@ -1,31 +1,51 @@
const { red, yellow } = require('chalk') const { red, yellow } = require('chalk')
const webpack = require('webpack')
const prefix = `[vue-server-renderer-webpack-plugin]` const prefix = `[vue-server-renderer-webpack-plugin]`
const warn = (exports.warn = (msg) => console.error(red(`${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`))) 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') { if (compiler.options.target !== 'node') {
warn('webpack config `target` should be "node".') warn('webpack config `target` should be "node".')
} }
if ( if (compiler.options.output) {
compiler.options.output && if (compiler.options.output.library) {
compiler.options.output.libraryTarget !== 'commonjs2' // Webpack >= 5.0.0
) { if (compiler.options.output.library.type !== 'commonjs2') {
warn('webpack config `output.libraryTarget` should be "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) { if (!compiler.options.externals) {
tip( tip(
'It is recommended to externalize dependencies in the server build for ' + 'It is recommended to externalize dependencies in the server build for ' +
'better build performance.' 'better build performance.'
) )
} }
} }
export const onEmit = (compiler, name, hook) => { export const onEmit = (compiler, name, stageName, hook) => {
if (compiler.hooks) { 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 // Webpack >= 4.0.0
compiler.hooks.emit.tapAsync(name, hook) compiler.hooks.emit.tapAsync(name, hook)
} else { } 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' export { isJS, isCSS } from '../util'

View File

@ -34,7 +34,7 @@ export function createWriteFunction(
defer(() => { defer(() => {
try { try {
next() next()
} catch (e) { } catch (e: any) {
onError(e) onError(e)
} }
}) })

View File

@ -34,7 +34,7 @@ export function isPrimitive(value: any): boolean {
/** /**
* Quick object check - this is primarily used to tell * 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. * is a JSON-compliant type.
*/ */
export function isObject(obj: any): boolean { export function isObject(obj: any): boolean {
@ -314,7 +314,7 @@ export function looseEqual(a: any, b: any): boolean {
/* istanbul ignore next */ /* istanbul ignore next */
return false return false
} }
} catch (e) { } catch (e: any) {
/* istanbul ignore next */ /* istanbul ignore next */
return false return false
} }

View File

@ -52,7 +52,7 @@ describe('SSR: basicRenderer', () => {
}) })
// #5941 // #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 let ssrContext
renderToString(new Vue({ renderToString(new Vue({
template: ` 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 => { it('everything together', done => {
renderVmWithOptions({ renderVmWithOptions({
template: ` template: `
@ -1323,7 +1351,7 @@ describe('SSR: renderToString', () => {
</div> </div>
` `
}, result => { }, result => {
expect(result).toContain(`<div class="a\nb"></div>`) expect(result).toContain(`<div class="a b"></div>`)
done() done()
}) })
}) })

View File

@ -7,7 +7,7 @@ describe('Component async', () => {
const oldClearTimeout = window.clearTimeout; const oldClearTimeout = window.clearTimeout;
// will contain pending timeouts set during the test iteration // 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 // this helps to identify the timeout that is still pending
let timeoutsPending = {}; let timeoutsPending = {};

View File

@ -572,6 +572,73 @@ describe('Component keep-alive', () => {
}).then(done) }).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', () => { it('should warn unknown component inside', () => {
new Vue({ new Vue({
template: `<keep-alive><foo/></keep-alive>` template: `<keep-alive><foo/></keep-alive>`
@ -1182,5 +1249,37 @@ describe('Component keep-alive', () => {
}).then(done) }).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`) expect(vm.$el.textContent).toMatch(`1`)
}).then(done) }).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') 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', () => { it('selector matching multiple elements', () => {
mount({ mount({
childTemplate: '<div><slot name="t"></slot></div>', 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>') expect(vm.$el.firstChild.innerHTML).toBe('<span><b>2</b></span>')
}).then(done) }).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) }).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 // a vdom patch edge case where the user has several un-keyed elements of the
// same tag next to each other, and toggling them. // same tag next to each other, and toggling them.
it('properly remove staticClass for toggling un-keyed children', done => { 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') expect(event.type).toBe('click')
}) })
it('should bind event to a inline statement', () => { it('should bind event to an inline statement', () => {
vm = new Vue({ vm = new Vue({
el, el,
template: '<div v-on:click="foo(1,2,3,$event)"></div>', template: '<div v-on:click="foo(1,2,3,$event)"></div>',
@ -218,7 +218,7 @@ describe('Directive v-on', () => {
}) })
// ctrl, shift, alt, meta // ctrl, shift, alt, meta
it('should support system modifers', () => { it('should support system modifiers', () => {
vm = new Vue({ vm = new Vue({
el, el,
template: ` template: `
@ -976,6 +976,17 @@ describe('Directive v-on', () => {
expect(value).toBe(1) 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', () => { describe('dynamic arguments', () => {
it('basic', done => { it('basic', done => {
const spy = jasmine.createSpy() const spy = jasmine.createSpy()

View File

@ -127,25 +127,25 @@ describe('Error handling', () => {
}).then(done) }).then(done)
}) })
it('should recover from errors in user watcher callback', done => { ;[
const vm = createTestInstance(components.userWatcherCallback) ['userWatcherCallback', 'watcher'],
vm.n++ ['userImmediateWatcherCallback', 'immediate watcher']
waitForUpdate(() => { ].forEach(([type, description]) => {
expect(`Error in callback for watcher "n"`).toHaveBeenWarned() it(`should recover from errors in user ${description} callback`, done => {
expect(`Error: userWatcherCallback`).toHaveBeenWarned() const vm = createTestInstance(components[type])
}).thenWaitFor(next => { assertBothInstancesActive(vm).then(() => {
assertBothInstancesActive(vm).end(next) expect(`Error in callback for ${description} "n"`).toHaveBeenWarned()
}).then(done) expect(`Error: ${type} error`).toHaveBeenWarned()
}) }).then(done)
})
it('should recover from errors in user immediate watcher callback', done => { it(`should recover from promise errors in user ${description} callback`, done => {
const vm = createTestInstance(components.userImmediateWatcherCallback) const vm = createTestInstance(components[`${type}Async`])
waitForUpdate(() => { assertBothInstancesActive(vm).then(() => {
expect(`Error in callback for immediate watcher "n"`).toHaveBeenWarned() expect(`Error in callback for ${description} "n" (Promise/async)`).toHaveBeenWarned()
expect(`Error: userImmediateWatcherCallback error`).toHaveBeenWarned() expect(`Error: ${type} error`).toHaveBeenWarned()
}).thenWaitFor(next => { }).then(done)
assertBothInstancesActive(vm).end(next) })
}).then(done)
}) })
it('config.errorHandler should capture render errors', 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 // event errors
components.event = { components.event = {
beforeCreate () { beforeCreate () {

View File

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

View File

@ -247,4 +247,152 @@ describe('Options errorCaptured', () => {
expect(store.errors[0]).toEqual(new Error('render error')) expect(store.errors[0]).toEqual(new Error('render error'))
}).then(done) }).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

@ -32,7 +32,7 @@ const webpackConfig = {
} }
}) })
], ],
devtool: '#inline-source-map' devtool: 'inline-source-map'
} }
// shared config for all unit tests // shared config for all unit tests

View File

@ -196,7 +196,7 @@ describe('codegen', () => {
it('generate slot fallback content', () => { it('generate slot fallback content', () => {
assertCodegen( assertCodegen(
'<div><slot><div>hi</div></slot></div>', '<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 Vue from 'vue'
import { SSR_ATTR } from 'shared/constants'
describe('vdom patch: edge cases', () => { describe('vdom patch: edge cases', () => {
// exposed by #3406 // exposed by #3406
@ -432,4 +433,22 @@ describe('vdom patch: edge cases', () => {
expect(vm.$el.textContent).not.toMatch('Infinity') expect(vm.$el.textContent).not.toMatch('Infinity')
}).then(done) }).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> | FunctionalComponentOptions<Props>
| ComponentOptions<never, Data, Methods, Computed, Props> | ComponentOptions<never, Data, Methods, Computed, Props>
interface EsModuleComponent { type EsModule<T> = T | { default: T }
default: Component
} 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> export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
= AsyncComponentPromise<Data, Methods, Computed, Props> = 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> = ( export type AsyncComponentPromise<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = (
resolve: (component: Component<Data, Methods, Computed, Props>) => void, resolve: (component: Component<Data, Methods, Computed, Props>) => void,
reject: (reason?: any) => 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> = () => { export type AsyncComponentFactory<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = () => {
component: AsyncComponentPromise<Data, Methods, Computed, Props>; component: Promise<ImportedComponent<Data, Methods, Computed, Props>>;
loading?: Component | EsModuleComponent; loading?: ImportedComponent;
error?: Component | EsModuleComponent; error?: ImportedComponent;
delay?: number; delay?: number;
timeout?: 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 $parent: Vue;
readonly $root: Vue; readonly $root: Vue;
readonly $children: 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 $slots: { [key: string]: VNode[] | undefined };
readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined }; readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined };
readonly $isServer: boolean; readonly $isServer: boolean;

View File

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

11894
yarn.lock

File diff suppressed because it is too large Load Diff