mirror of
https://gitee.com/vuejs/vue.git
synced 2024-11-30 02:57:43 +08:00
chore: merge
This commit is contained in:
commit
ec1f7309f3
@ -11,7 +11,7 @@
|
||||
flow
|
||||
|
||||
[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='^core/\(.*\)$' -> '<PROJECT_ROOT>/src/core/\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='^entries/\(.*\)$' -> '<PROJECT_ROOT>/src/entries/\1'
|
||||
module.name_mapper='^sfc/\(.*\)$' -> '<PROJECT_ROOT>/src/sfc/\1'
|
||||
suppress_comment= \\(.\\|\n\\)*\\$flow-disable-line
|
||||
# suppress_comment= \\(.\\|\n\\)*\\$flow-disable-line
|
||||
|
10
.github/CONTRIBUTING.md
vendored
10
.github/CONTRIBUTING.md
vendored
@ -124,15 +124,7 @@ The default test script will do the following: lint with ESLint -> type check wi
|
||||
|
||||
## Financial Contribution
|
||||
|
||||
As a pure community-driven project without major corporate backing, we also welcome financial contributions via Patreon and OpenCollective.
|
||||
|
||||
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou)
|
||||
- [Become a backer or sponsor on OpenCollective](https://opencollective.com/vuejs)
|
||||
- [One-time donation via PayPal or crypto-currencies](https://vuejs.org/support-vuejs/#One-time-Donations)
|
||||
|
||||
### What's the difference between Patreon and OpenCollective funding?
|
||||
|
||||
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
|
||||
As a pure community-driven project without major corporate backing, we also welcome financial contributions via GitHub Sponsors and OpenCollective. Please consult the [Sponsor Page](https://vuejs.org/sponsor/) for more details.
|
||||
|
||||
## Credits
|
||||
|
||||
|
485
BACKERS.md
485
BACKERS.md
@ -1,488 +1,9 @@
|
||||
<h1 align="center">Sponsors & Backers</h1>
|
||||
|
||||
Vue.js is an MIT-licensed open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider:
|
||||
|
||||
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou).
|
||||
- [Become a backer or sponsor on OpenCollective](https://opencollective.com/vuejs).
|
||||
- [One-time donation via PayPal or crypto-currencies.](https://vuejs.org/support-vuejs/#One-time-Donations)
|
||||
|
||||
#### What's the difference between Patreon and OpenCollective?
|
||||
|
||||
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
|
||||
|
||||
<br><br>
|
||||
|
||||
<h2 align="center">Special Sponsors</h2>
|
||||
|
||||
<!--special start-->
|
||||
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of the awesome sponsors and backers listed in this file. If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/).
|
||||
|
||||
<p align="center">
|
||||
<a href="https://autocode.com/" target="_blank">
|
||||
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true">
|
||||
<a target="_blank" href="https://sponsors.vuejs.org/backers.svg">
|
||||
<img alt="sponsors" src="https://sponsors.vuejs.org/backers.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<!--special end-->
|
||||
|
||||
<h2 align="center">Platinum via Patreon</h2>
|
||||
|
||||
<!--platinum start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vueschool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vehikl.com/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vehikl.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/retool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://passionatepeople.io/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/passionate_people.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.storyblok.com" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/storyblok.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/ionic.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://nuxtjs.org/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/nuxt.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--platinum end-->
|
||||
|
||||
<!--special-china start-->
|
||||
<h3 align="center">Platinum Sponsors (China)</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank">
|
||||
<img width="177px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/dcloud.gif">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--special-china end-->
|
||||
|
||||
<h2 align="center">Platinum via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/avatar.svg"></a>
|
||||
|
||||
<h2 align="center">Gold via Patreon</h2>
|
||||
|
||||
<!--gold start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vuemastery.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuemastery.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://laravel.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/laravel.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://htmlburger.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/html_burger.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.frontenddeveloperlove.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/frontendlove.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neds.com.au/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/neds.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://icons8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/icons_8.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vuejobs.com/?ref=vuejs" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuejobs.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tidelift.com/subscription/npm/vue" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tidelift.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.firesticktricks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/firestick_tricks.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://intygrate.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/intygrate.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://en.shopware.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/shopware_ag.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpnranks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpnranks.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bacancytechnology.com/hire-vuejs-developer" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bacancy_technology.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bestvpn.co/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bestvpn_co.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.y8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/y8.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://js.devexpress.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/devexpress.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://fastcoding.jp/javascript/ " target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/fastcoding_inc.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://usave.co.uk/utilities/broadband" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/usave.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foo.software" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/foo.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://flatlogic.com/templates" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/flatlogic_templates.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://moovweb.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/moovweb.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vpn-review.com/netflix-vpn" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpn_review.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://cosmos.network/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tendermint.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.okayhq.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/okay.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpsserver.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpsserver_com.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://aussiecasinohex.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/aussiecasinohex.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://litslink.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/litslink.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://newicon.net" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/newicon.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://lowdefy.com?k=w432" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/lowdefy.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://quickbookstoolhub.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/quickbooks_tool_hub.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--gold end-->
|
||||
|
||||
<h2 align="center">Gold via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/0/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/1/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/2/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/2/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/3/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/3/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/4/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/4/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/5/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/5/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/6/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/6/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/7/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/7/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/8/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/8/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/9/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/9/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/10/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/10/avatar.svg" height="60px"></a>
|
||||
|
||||
<h2 align="center">Silver via Patreon</h2>
|
||||
|
||||
- Matt Mullenweg
|
||||
|
||||
<!--silver start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://roadster.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/roadster.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.inkoop.io" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/inkoop.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.thecasinodb.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/isolutions_uk_limited.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://teamextension.io" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/team_extension_north_america_inc.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://freebets.us" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/free_bets_us.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://betting.bet" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/betting_bet.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--silver end-->
|
||||
|
||||
<h4 align="center">Silver via OpenCollective</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/2/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/2/avatar.svg"></a>
|
||||
|
||||
<h2 align="center">Bronze via Patreon</h2>
|
||||
|
||||
<!--bronze start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.accelebrate.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/accelebrate.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://polyglotengineer.com/derek.pollard" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/derek_pollard.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.earthlink.ro" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/earthlink.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.webucator.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/webucator.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://memberful.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/memberful.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--bronze end-->
|
||||
|
||||
<h2 align="center">Bronze via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/2/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/3/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/4/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/5/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/6/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/7/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/8/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/9/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/9/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/10/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/10/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/11/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/11/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/12/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/12/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/13/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/13/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/14/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/14/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/15/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/15/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/16/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/16/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/17/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/17/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/18/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/18/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/19/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/19/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/20/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/20/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/21/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/21/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/22/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/22/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/23/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/23/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/24/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/24/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/25/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/25/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/26/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/26/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/27/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/27/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/28/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/28/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/29/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/29/avatar.svg"></a>
|
||||
|
||||
<h2 align="center">Generous Backers via Patreon ($50+)</h2>
|
||||
|
||||
<!--50 start-->
|
||||
- Yoshitaka M
|
||||
- Peter Imburg
|
||||
- Sean Ferguson
|
||||
- Johnny Ray Austin
|
||||
- errorrik
|
||||
- Wasim Khamlichi
|
||||
<!--50 end-->
|
||||
|
||||
<h2 align="center">Backers via Patreon</h2>
|
||||
|
||||
<!--10 start-->
|
||||
- Sara McVey
|
||||
- Keisuke Kita
|
||||
- Alex Riviere
|
||||
- Thomas Sittig
|
||||
- WhereJuly
|
||||
- Fontis
|
||||
- Jack
|
||||
- Nick Carr
|
||||
- Artur Bańka
|
||||
- Traversy Media
|
||||
- Pierre Baron
|
||||
- Donghai Gai
|
||||
- Aleksander Figiel
|
||||
- Faizal Andyka
|
||||
- wickedwei
|
||||
- Sunny Yuen
|
||||
- Jules
|
||||
- Zeth Odderskov
|
||||
- Santi Sanchez Canals
|
||||
- Thomas Wiedemann
|
||||
- Nobuhide Esaki
|
||||
- Roy Segall
|
||||
- Allan McKernan
|
||||
- 琚致远
|
||||
- Diana Bergholz
|
||||
- Riki Fridrich
|
||||
- Alfonso Herrera
|
||||
- Bichinger Software & Consulting
|
||||
- username
|
||||
- Pierre Lebrun
|
||||
- Peter Matkovsky
|
||||
- 龙腾道
|
||||
- Nick Dandakis
|
||||
- Yusuke Kawabata
|
||||
- Shawn Wildermuth
|
||||
- Andrew Willis
|
||||
- Elon Hung
|
||||
- Роман Латкин
|
||||
- Juan Bermudez
|
||||
- Hannes Kochniß
|
||||
- Daniel Mattingley
|
||||
- Matt Sencenbaugh
|
||||
- Jaeyoung Lee
|
||||
- David Kaplan
|
||||
- David Ang
|
||||
- Wakana Seki
|
||||
- Jere Sjöroos
|
||||
- Donald Fischer
|
||||
- Eric
|
||||
- tyler madsen
|
||||
- Joe Gregory
|
||||
- Masahiro Tanaka
|
||||
- Tyler
|
||||
- IMGNRY
|
||||
- Jim Raden
|
||||
- Haim Yulzari
|
||||
- Anthony Estebe
|
||||
- Asaf Yishai
|
||||
- Jon Hobbs-Smith
|
||||
- Pierre Vanhulst
|
||||
- Zoran Knezevic
|
||||
- Luiz
|
||||
- Bernhard E. Reiter
|
||||
- Guy Gavergun
|
||||
- Matt Jones
|
||||
- Niannian Modisette
|
||||
- Matsumoto Takamasa
|
||||
- Barbara Liau
|
||||
- Wen-Tien Chang
|
||||
- Stephen Michael Hartley
|
||||
- Victor Tolbert
|
||||
- Lars Andreas Ness
|
||||
- Benjamin Listwon
|
||||
- Chris Calo
|
||||
<!--10 end-->
|
||||
|
||||
<h2 align="center">Backers via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs#backers" target="_blank"><img src="https://opencollective.com/vuejs/backers.svg?width=890"></a>
|
||||
|
275
README.md
275
README.md
@ -7,280 +7,22 @@
|
||||
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/v/vue.svg?sanitize=true" alt="Version"></a>
|
||||
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/l/vue.svg?sanitize=true" alt="License"></a>
|
||||
<a href="https://chat.vuejs.org/"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true" alt="Chat"></a>
|
||||
<br>
|
||||
<a href="https://app.saucelabs.com/builds/50f8372d79f743a3b25fb6ca4851ca4c"><img src="https://app.saucelabs.com/buildstatus/vuejs" alt="Build Status"></a>
|
||||
</p>
|
||||
|
||||
<h2 align="center">Supporting Vue.js</h2>
|
||||
## This repo is for Vue 2
|
||||
|
||||
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider:
|
||||
You are looking at the repository for Vue 2. The repo for Vue 3 is [vuejs/core](https://github.com/vuejs/core).
|
||||
|
||||
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou).
|
||||
- [Become a backer or sponsor on Open Collective](https://opencollective.com/vuejs).
|
||||
- [One-time donation via PayPal or crypto-currencies.](https://vuejs.org/support-vuejs/#One-time-Donations)
|
||||
## Sponsors
|
||||
|
||||
#### What's the difference between Patreon and OpenCollective?
|
||||
|
||||
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
|
||||
|
||||
<h3 align="center">Special Sponsors</h3>
|
||||
<!--special start-->
|
||||
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/core/blob/main/BACKERS.md). If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/).
|
||||
|
||||
<p align="center">
|
||||
<a href="https://autocode.com/" target="_blank">
|
||||
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true">
|
||||
<a target="_blank" href="https://vuejs.org/sponsor/">
|
||||
<img alt="sponsors" src="https://sponsors.vuejs.org/sponsors.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<!--special end-->
|
||||
|
||||
<h3 align="center">Platinum Sponsors</h3>
|
||||
|
||||
<!--platinum start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vueschool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vehikl.com/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vehikl.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/retool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://passionatepeople.io/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/passionate_people.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.storyblok.com" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/storyblok.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/ionic.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://nuxtjs.org/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/nuxt.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--platinum end-->
|
||||
|
||||
<!--special-china start-->
|
||||
<h3 align="center">Platinum Sponsors (China)</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank">
|
||||
<img width="177px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/dcloud.gif">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--special-china end-->
|
||||
|
||||
<h3 align="center">Gold Sponsors</h3>
|
||||
|
||||
<!--gold start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vuemastery.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuemastery.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://laravel.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/laravel.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://htmlburger.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/html_burger.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.frontenddeveloperlove.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/frontendlove.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neds.com.au/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/neds.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://icons8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/icons_8.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vuejobs.com/?ref=vuejs" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuejobs.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tidelift.com/subscription/npm/vue" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tidelift.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.firesticktricks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/firestick_tricks.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://intygrate.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/intygrate.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://en.shopware.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/shopware_ag.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpnranks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpnranks.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bacancytechnology.com/hire-vuejs-developer" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bacancy_technology.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bestvpn.co/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bestvpn_co.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.y8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/y8.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://js.devexpress.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/devexpress.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://fastcoding.jp/javascript/ " target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/fastcoding_inc.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://usave.co.uk/utilities/broadband" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/usave.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foo.software" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/foo.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://flatlogic.com/templates" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/flatlogic_templates.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://moovweb.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/moovweb.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vpn-review.com/netflix-vpn" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpn_review.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://cosmos.network/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tendermint.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.okayhq.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/okay.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpsserver.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpsserver_com.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://aussiecasinohex.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/aussiecasinohex.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://litslink.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/litslink.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://newicon.net" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/newicon.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://lowdefy.com?k=w432" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/lowdefy.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://quickbookstoolhub.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/quickbooks_tool_hub.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--gold end-->
|
||||
|
||||
<h3 align="center">Sponsors via <a href="https://opencollective.com/vuejs">Open Collective</a></h3>
|
||||
|
||||
<h4 align="center">Platinum</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/avatar.svg?sanitize=true"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/avatar.svg?sanitize=true"></a>
|
||||
|
||||
<h4 align="center">Gold</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/0/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/1/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/2/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/2/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/3/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/3/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/4/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/4/avatar.svg?sanitize=true" height="60px"></a>
|
||||
|
||||
---
|
||||
|
||||
## Introduction
|
||||
@ -294,7 +36,7 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
|
||||
## Ecosystem
|
||||
|
||||
| Project | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
|
||||
| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing |
|
||||
| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management |
|
||||
| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding |
|
||||
@ -312,7 +54,6 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
|
||||
[vue-class-component]: https://github.com/vuejs/vue-class-component
|
||||
[vue-rx]: https://github.com/vuejs/vue-rx
|
||||
[vue-devtools]: https://github.com/vuejs/vue-devtools
|
||||
|
||||
[vue-router-status]: https://img.shields.io/npm/v/vue-router.svg
|
||||
[vuex-status]: https://img.shields.io/npm/v/vuex.svg
|
||||
[vue-cli-status]: https://img.shields.io/npm/v/@vue/cli.svg
|
||||
@ -321,7 +62,6 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
|
||||
[vue-class-component-status]: https://img.shields.io/npm/v/vue-class-component.svg
|
||||
[vue-rx-status]: https://img.shields.io/npm/v/vue-rx.svg
|
||||
[vue-devtools-status]: https://img.shields.io/chrome-web-store/v/nhdogjmejiglipccpnnnanhbledajbpd.svg
|
||||
|
||||
[vue-router-package]: https://npmjs.com/package/vue-router
|
||||
[vuex-package]: https://npmjs.com/package/vuex
|
||||
[vue-cli-package]: https://npmjs.com/package/@vue/cli
|
||||
@ -361,7 +101,6 @@ Thank you to all the people who already contributed to Vue!
|
||||
|
||||
<a href="https://github.com/vuejs/vue/graphs/contributors"><img src="https://opencollective.com/vuejs/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://opensource.org/licenses/MIT)
|
||||
|
4512
dist/vue.common.dev.js
vendored
4512
dist/vue.common.dev.js
vendored
File diff suppressed because it is too large
Load Diff
10
dist/vue.common.prod.js
vendored
10
dist/vue.common.prod.js
vendored
File diff suppressed because one or more lines are too long
819
dist/vue.esm.browser.js
vendored
819
dist/vue.esm.browser.js
vendored
File diff suppressed because it is too large
Load Diff
10
dist/vue.esm.browser.min.js
vendored
10
dist/vue.esm.browser.min.js
vendored
File diff suppressed because one or more lines are too long
4549
dist/vue.esm.js
vendored
4549
dist/vue.esm.js
vendored
File diff suppressed because it is too large
Load Diff
4490
dist/vue.js
vendored
4490
dist/vue.js
vendored
File diff suppressed because it is too large
Load Diff
10
dist/vue.min.js
vendored
10
dist/vue.min.js
vendored
File diff suppressed because one or more lines are too long
2831
dist/vue.runtime.common.dev.js
vendored
2831
dist/vue.runtime.common.dev.js
vendored
File diff suppressed because it is too large
Load Diff
10
dist/vue.runtime.common.prod.js
vendored
10
dist/vue.runtime.common.prod.js
vendored
File diff suppressed because one or more lines are too long
2867
dist/vue.runtime.esm.js
vendored
2867
dist/vue.runtime.esm.js
vendored
File diff suppressed because it is too large
Load Diff
2809
dist/vue.runtime.js
vendored
2809
dist/vue.runtime.js
vendored
File diff suppressed because it is too large
Load Diff
10
dist/vue.runtime.min.js
vendored
10
dist/vue.runtime.min.js
vendored
File diff suppressed because one or more lines are too long
164
package.json
164
package.json
@ -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 it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,16 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
|
||||
var isCSS = function (file) { return /\.css(\?[^.]+)?$/.test(file); };
|
||||
const isJS = (file) => /\.js(\?[^.]+)?$/.test(file);
|
||||
const isCSS = (file) => /\.css(\?[^.]+)?$/.test(file);
|
||||
|
||||
var ref = require('chalk');
|
||||
var red = ref.red;
|
||||
var yellow = ref.yellow;
|
||||
var prefix = "[vue-server-renderer-webpack-plugin]";
|
||||
(exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); });
|
||||
(exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); });
|
||||
var onEmit = function (compiler, name, hook) {
|
||||
if (compiler.hooks) {
|
||||
const { red, yellow } = require('chalk');
|
||||
const webpack = require('webpack');
|
||||
const prefix = `[vue-server-renderer-webpack-plugin]`;
|
||||
exports.warn = msg => console.error(red(`${prefix} ${msg}\n`));
|
||||
exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`));
|
||||
const isWebpack5 = !!(webpack.version && webpack.version[0] > 4);
|
||||
const onEmit = (compiler, name, stageName, hook) => {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
compiler.hooks.compilation.tap(name, compilation => {
|
||||
if (compilation.compiler !== compiler) {
|
||||
// Ignore child compilers
|
||||
return;
|
||||
}
|
||||
const stage = webpack.Compilation[stageName];
|
||||
compilation.hooks.processAssets.tapAsync({ name, stage }, (assets, cb) => {
|
||||
hook(compilation, cb);
|
||||
});
|
||||
});
|
||||
}
|
||||
else if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook);
|
||||
}
|
||||
@ -19,31 +32,44 @@ var onEmit = function (compiler, name, hook) {
|
||||
compiler.plugin('emit', hook);
|
||||
}
|
||||
};
|
||||
|
||||
var hash = require('hash-sum');
|
||||
var uniq = require('lodash.uniq');
|
||||
var VueSSRClientPlugin = function VueSSRClientPlugin(options) {
|
||||
if ( options === void 0 ) options = {};
|
||||
|
||||
//@ts-expect-error
|
||||
this.options = Object.assign({
|
||||
filename: 'vue-ssr-client-manifest.json',
|
||||
}, options);
|
||||
const stripModuleIdHash = id => {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
return id.replace(/\|\w+$/, '');
|
||||
}
|
||||
// Webpack < 5.0.0
|
||||
return id.replace(/\s\w+$/, '');
|
||||
};
|
||||
const getAssetName = asset => {
|
||||
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) {
|
||||
var stats = compilation.getStats().toJson();
|
||||
var allFiles = uniq(stats.assets.map(function (a) { return a.name; }));
|
||||
var initialFiles = uniq(Object.keys(stats.entrypoints)
|
||||
.map(function (name) { return stats.entrypoints[name].assets; })
|
||||
.reduce(function (assets, all) { return all.concat(assets); }, [])
|
||||
.filter(function (file) { return isJS(file) || isCSS(file); }));
|
||||
var asyncFiles = allFiles
|
||||
.filter(function (file) { return isJS(file) || isCSS(file); })
|
||||
.filter(function (file) { return initialFiles.indexOf(file) < 0; });
|
||||
var manifest = {
|
||||
const hash = require("hash-sum");
|
||||
const uniq = require("lodash.uniq");
|
||||
class VueSSRClientPlugin {
|
||||
constructor(options = {}) {
|
||||
//@ts-expect-error no type on 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,
|
||||
@ -52,34 +78,36 @@ VueSSRClientPlugin.prototype.apply = function apply (compiler) {
|
||||
/* [identifier: string]: Array<index: number> */
|
||||
},
|
||||
};
|
||||
var assetModules = stats.modules.filter(function (m) { return m.assets.length; });
|
||||
var fileToIndex = function (file) { return manifest.all.indexOf(file); };
|
||||
stats.modules.forEach(function (m) {
|
||||
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) {
|
||||
var cid = m.chunks[0];
|
||||
var chunk = stats.chunks.find(function (c) { return c.id === cid; });
|
||||
const cid = m.chunks[0];
|
||||
const chunk = stats.chunks.find((c) => c.id === cid);
|
||||
if (!chunk || !chunk.files) {
|
||||
return;
|
||||
}
|
||||
var id = m.identifier.replace(/\s\w+$/, ''); // remove appended hash
|
||||
var files = (manifest.modules[hash(id)] = chunk.files.map(fileToIndex));
|
||||
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(function (m) {
|
||||
if (m.chunks.some(function (id) { return id === cid; })) {
|
||||
assetModules.forEach((m) => {
|
||||
if (m.chunks.some((id) => id === cid)) {
|
||||
files.push.apply(files, m.assets.map(fileToIndex));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
var json = JSON.stringify(manifest, null, 2);
|
||||
//@ts-expect-error
|
||||
compilation.assets[this$1.options.filename] = {
|
||||
source: function () { return json; },
|
||||
size: function () { return json.length; },
|
||||
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();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VueSSRClientPlugin;
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue-server-renderer",
|
||||
"version": "2.6.12",
|
||||
"version": "2.6.14",
|
||||
"description": "server renderer for Vue 2.0",
|
||||
"main": "index.js",
|
||||
"types": "types/index.d.ts",
|
||||
|
@ -1,28 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
|
||||
const isJS = (file) => /\.js(\?[^.]+)?$/.test(file);
|
||||
|
||||
var ref = require('chalk');
|
||||
var red = ref.red;
|
||||
var yellow = ref.yellow;
|
||||
var prefix = "[vue-server-renderer-webpack-plugin]";
|
||||
var warn = (exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); });
|
||||
var tip = (exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); });
|
||||
var validate = function (compiler) {
|
||||
const { red, yellow } = require('chalk');
|
||||
const webpack = require('webpack');
|
||||
const prefix = `[vue-server-renderer-webpack-plugin]`;
|
||||
const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`));
|
||||
const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`));
|
||||
const isWebpack5 = !!(webpack.version && webpack.version[0] > 4);
|
||||
const validate = compiler => {
|
||||
if (compiler.options.target !== 'node') {
|
||||
warn('webpack config `target` should be "node".');
|
||||
}
|
||||
if (compiler.options.output &&
|
||||
compiler.options.output.libraryTarget !== 'commonjs2') {
|
||||
if (compiler.options.output) {
|
||||
if (compiler.options.output.library) {
|
||||
// Webpack >= 5.0.0
|
||||
if (compiler.options.output.library.type !== 'commonjs2') {
|
||||
warn('webpack config `output.library.type` should be "commonjs2".');
|
||||
}
|
||||
}
|
||||
else if (compiler.options.output.libraryTarget !== 'commonjs2') {
|
||||
// Webpack < 5.0.0
|
||||
warn('webpack config `output.libraryTarget` should be "commonjs2".');
|
||||
}
|
||||
}
|
||||
if (!compiler.options.externals) {
|
||||
tip('It is recommended to externalize dependencies in the server build for ' +
|
||||
'better build performance.');
|
||||
}
|
||||
};
|
||||
var onEmit = function (compiler, name, hook) {
|
||||
if (compiler.hooks) {
|
||||
const onEmit = (compiler, name, stageName, hook) => {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
compiler.hooks.compilation.tap(name, compilation => {
|
||||
if (compilation.compiler !== compiler) {
|
||||
// Ignore child compilers
|
||||
return;
|
||||
}
|
||||
const stage = webpack.Compilation[stageName];
|
||||
compilation.hooks.processAssets.tapAsync({ name, stage }, (assets, cb) => {
|
||||
hook(compilation, cb);
|
||||
});
|
||||
});
|
||||
}
|
||||
else if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook);
|
||||
}
|
||||
@ -31,60 +52,67 @@ var onEmit = function (compiler, name, hook) {
|
||||
compiler.plugin('emit', hook);
|
||||
}
|
||||
};
|
||||
const getAssetName = asset => {
|
||||
if (typeof asset === 'string') {
|
||||
return asset;
|
||||
}
|
||||
return asset.name;
|
||||
};
|
||||
|
||||
var VueSSRServerPlugin = function VueSSRServerPlugin(options) {
|
||||
if ( options === void 0 ) options = {};
|
||||
|
||||
class VueSSRServerPlugin {
|
||||
constructor(options = {}) {
|
||||
//@ts-expect-error
|
||||
this.options = Object.assign({
|
||||
filename: 'vue-ssr-server-bundle.json',
|
||||
}, options);
|
||||
};
|
||||
VueSSRServerPlugin.prototype.apply = function apply (compiler) {
|
||||
var this$1 = this;
|
||||
|
||||
}
|
||||
apply(compiler) {
|
||||
validate(compiler);
|
||||
onEmit(compiler, 'vue-server-plugin', function (compilation, cb) {
|
||||
var stats = compilation.getStats().toJson();
|
||||
var entryName = Object.keys(stats.entrypoints)[0];
|
||||
var entryInfo = stats.entrypoints[entryName];
|
||||
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();
|
||||
}
|
||||
var entryAssets = entryInfo.assets.filter(isJS);
|
||||
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.");
|
||||
throw new Error(`Server-side bundle should have one single entry file. ` +
|
||||
`Avoid using CommonsChunkPlugin in the server config.`);
|
||||
}
|
||||
var entry = entryAssets[0];
|
||||
const entry = entryAssets[0];
|
||||
if (!entry || typeof entry !== 'string') {
|
||||
throw new Error(("Entry \"" + entryName + "\" not found. Did you specify the correct entry option?"));
|
||||
throw new Error(`Entry "${entryName}" not found. Did you specify the correct entry option?`);
|
||||
}
|
||||
var bundle = {
|
||||
entry: entry,
|
||||
const bundle = {
|
||||
entry,
|
||||
files: {},
|
||||
maps: {},
|
||||
};
|
||||
stats.assets.forEach(function (asset) {
|
||||
if (isJS(asset.name)) {
|
||||
bundle.files[asset.name] = compilation.assets[asset.name].source();
|
||||
Object.keys(compilation.assets).forEach(name => {
|
||||
if (isJS(name)) {
|
||||
bundle.files[name] = compilation.assets[name].source();
|
||||
}
|
||||
else if (asset.name.match(/\.js\.map$/)) {
|
||||
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[asset.name].source());
|
||||
else if (name.match(/\.js\.map$/)) {
|
||||
bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source());
|
||||
}
|
||||
// do not emit anything else for server
|
||||
delete compilation.assets[asset.name];
|
||||
delete compilation.assets[name];
|
||||
});
|
||||
var json = JSON.stringify(bundle, null, 2);
|
||||
const json = JSON.stringify(bundle, null, 2);
|
||||
//@ts-expect-error
|
||||
var filename = this$1.options.filename;
|
||||
const filename = this.options.filename;
|
||||
compilation.assets[filename] = {
|
||||
source: function () { return json; },
|
||||
size: function () { return json.length; },
|
||||
source: () => json,
|
||||
size: () => json.length,
|
||||
};
|
||||
cb();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VueSSRServerPlugin;
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { Plugin } from 'webpack';
|
||||
import { DefinePlugin } from 'webpack';
|
||||
|
||||
interface WebpackPluginOptions {
|
||||
filename?: string;
|
||||
}
|
||||
|
||||
export interface WebpackPlugin {
|
||||
new (options?: WebpackPluginOptions): Plugin;
|
||||
// NOTE NOT SURE ABOUT THIS
|
||||
// TODO DOUBLE CHECK HERE
|
||||
new (options?: WebpackPluginOptions): DefinePlugin;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue-template-compiler",
|
||||
"version": "2.6.12",
|
||||
"version": "2.6.14",
|
||||
"description": "template compiler for Vue 2.0",
|
||||
"main": "index.js",
|
||||
"unpkg": "browser.js",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,59 +2,72 @@
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
/* */
|
||||
|
||||
// this will be preserved during build
|
||||
// $flow-disable-line
|
||||
var VueFactory = require('./factory');
|
||||
|
||||
var instanceOptions = {};
|
||||
|
||||
/**
|
||||
* Create instance context.
|
||||
*/
|
||||
function createInstanceContext(instanceId, runtimeContext, data) {
|
||||
if (data === void 0) { data = {}; }
|
||||
function createInstanceContext (
|
||||
instanceId,
|
||||
runtimeContext,
|
||||
data
|
||||
) {
|
||||
if ( data === void 0 ) data = {};
|
||||
|
||||
var weex = runtimeContext.weex;
|
||||
var instance = (instanceOptions[instanceId] = {
|
||||
var instance = instanceOptions[instanceId] = {
|
||||
instanceId: instanceId,
|
||||
config: weex.config,
|
||||
document: weex.document,
|
||||
data: data,
|
||||
});
|
||||
// Each instance has a independent `Vue` module instance
|
||||
var Vue = (instance.Vue = createVueModuleInstance(instanceId, weex));
|
||||
data: data
|
||||
};
|
||||
|
||||
// Each instance has an independent `Vue` module instance
|
||||
var Vue = instance.Vue = createVueModuleInstance(instanceId, weex);
|
||||
|
||||
// DEPRECATED
|
||||
var timerAPIs = getInstanceTimer(instanceId, weex.requireModule);
|
||||
|
||||
var instanceContext = Object.assign({ Vue: Vue }, timerAPIs);
|
||||
Object.freeze(instanceContext);
|
||||
return instanceContext;
|
||||
return instanceContext
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy an instance with id. It will make sure all memory of
|
||||
* this instance released and no more leaks.
|
||||
*/
|
||||
function destroyInstance(instanceId) {
|
||||
function destroyInstance (instanceId) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
//@ts-expect-error
|
||||
if (instance && instance.app instanceof instance.Vue) {
|
||||
try {
|
||||
instance.app.$destroy();
|
||||
instance.document.destroy();
|
||||
}
|
||||
catch (e) { }
|
||||
//@ts-expect-error
|
||||
} catch (e) {}
|
||||
delete instance.document;
|
||||
delete instance.app;
|
||||
}
|
||||
delete instanceOptions[instanceId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an instance with id and new top-level component data.
|
||||
* It will use `Vue.set` on all keys of the new data. So it's better
|
||||
* define all possible meaningful keys when instance created.
|
||||
*/
|
||||
function refreshInstance(instanceId, data) {
|
||||
function refreshInstance (
|
||||
instanceId,
|
||||
data
|
||||
) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
//@ts-expect-error
|
||||
if (!instance || !(instance.app instanceof instance.Vue)) {
|
||||
return new Error("refreshInstance: instance " + instanceId + " not found!");
|
||||
return new Error(("refreshInstance: instance " + instanceId + " not found!"))
|
||||
}
|
||||
if (instance.Vue && instance.Vue.set) {
|
||||
for (var key in data) {
|
||||
@ -64,36 +77,44 @@ function refreshInstance(instanceId, data) {
|
||||
// Finally `refreshFinish` signal needed.
|
||||
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fresh instance of Vue for each Weex instance.
|
||||
*/
|
||||
function createVueModuleInstance(instanceId, weex) {
|
||||
function createVueModuleInstance (
|
||||
instanceId,
|
||||
weex
|
||||
) {
|
||||
var exports = {};
|
||||
VueFactory(exports, weex.document);
|
||||
//@ts-expect-error
|
||||
var Vue = exports.Vue;
|
||||
|
||||
var instance = instanceOptions[instanceId];
|
||||
|
||||
// patch reserved tag detection to account for dynamically registered
|
||||
// components
|
||||
var weexRegex = /^weex:/i;
|
||||
var isReservedTag = Vue.config.isReservedTag || (function () { return false; });
|
||||
var isRuntimeComponent = Vue.config.isRuntimeComponent || (function () { return false; });
|
||||
Vue.config.isReservedTag = function (name) {
|
||||
return ((!isRuntimeComponent(name) && weex.supports("@component/" + name)) ||
|
||||
return (!isRuntimeComponent(name) && weex.supports(("@component/" + name))) ||
|
||||
isReservedTag(name) ||
|
||||
weexRegex.test(name));
|
||||
weexRegex.test(name)
|
||||
};
|
||||
Vue.config.parsePlatformTagName = function (name) { return name.replace(weexRegex, ''); };
|
||||
|
||||
// expose weex-specific info
|
||||
Vue.prototype.$instanceId = instanceId;
|
||||
Vue.prototype.$document = instance.document;
|
||||
|
||||
// expose weex native module getter on subVue prototype so that
|
||||
// vdom runtime modules can access native modules via vnode.context
|
||||
Vue.prototype.$requireWeexModule = weex.requireModule;
|
||||
|
||||
// Hack `Vue` behavior to handle instance information and data
|
||||
// before root component created.
|
||||
Vue.mixin({
|
||||
beforeCreate: function () {
|
||||
beforeCreate: function beforeCreate () {
|
||||
var options = this.$options;
|
||||
// root component (vm)
|
||||
if (options.el) {
|
||||
@ -105,18 +126,18 @@ function createVueModuleInstance(instanceId, weex) {
|
||||
instance.app = this;
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
mounted: function mounted () {
|
||||
var options = this.$options;
|
||||
// root component (vm)
|
||||
if (options.el && weex.document && instance.app === this) {
|
||||
try {
|
||||
// Send "createFinish" signal to native.
|
||||
weex.document.taskCenter.send('dom', { action: 'createFinish' }, []);
|
||||
} catch (e) {}
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @deprecated Just instance variable `weex.config`
|
||||
* Get instance config.
|
||||
@ -124,11 +145,13 @@ function createVueModuleInstance(instanceId, weex) {
|
||||
*/
|
||||
Vue.prototype.$getConfig = function () {
|
||||
if (instance.app instanceof Vue) {
|
||||
return instance.config;
|
||||
return instance.config
|
||||
}
|
||||
};
|
||||
return Vue;
|
||||
|
||||
return Vue
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
* Generate HTML5 Timer APIs. An important point is that the callback
|
||||
@ -136,46 +159,43 @@ function createVueModuleInstance(instanceId, weex) {
|
||||
* framework can make sure no side effect of the callback happened after
|
||||
* an instance destroyed.
|
||||
*/
|
||||
function getInstanceTimer(instanceId, moduleGetter) {
|
||||
function getInstanceTimer (
|
||||
instanceId,
|
||||
moduleGetter
|
||||
) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
var timer = moduleGetter('timer');
|
||||
var timerAPIs = {
|
||||
setTimeout: function () {
|
||||
var arguments$1 = arguments;
|
||||
var args = [], len = arguments.length;
|
||||
while ( len-- ) args[ len ] = arguments[ len ];
|
||||
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments$1[_i];
|
||||
}
|
||||
var handler = function () {
|
||||
args[0].apply(args, args.slice(2));
|
||||
};
|
||||
|
||||
timer.setTimeout(handler, args[1]);
|
||||
//@ts-expect-error
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString();
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
|
||||
},
|
||||
setInterval: function () {
|
||||
var arguments$1 = arguments;
|
||||
var args = [], len = arguments.length;
|
||||
while ( len-- ) args[ len ] = arguments[ len ];
|
||||
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments$1[_i];
|
||||
}
|
||||
var handler = function () {
|
||||
args[0].apply(args, args.slice(2));
|
||||
};
|
||||
|
||||
timer.setInterval(handler, args[1]);
|
||||
//@ts-expect-error
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString();
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
|
||||
},
|
||||
clearTimeout: function (n) {
|
||||
timer.clearTimeout(n);
|
||||
},
|
||||
clearInterval: function (n) {
|
||||
timer.clearInterval(n);
|
||||
},
|
||||
}
|
||||
};
|
||||
return timerAPIs;
|
||||
return timerAPIs
|
||||
}
|
||||
|
||||
exports.createInstanceContext = createInstanceContext;
|
||||
|
@ -267,9 +267,9 @@ function genConfig (name) {
|
||||
vars.preventAssignment = true
|
||||
config.plugins.push(replace(vars))
|
||||
|
||||
if (opts.transpile !== false) {
|
||||
config.plugins.push(buble())
|
||||
}
|
||||
// if (opts.transpile !== false) {
|
||||
// config.plugins.push(buble())
|
||||
// }
|
||||
|
||||
Object.defineProperty(config, '_name', {
|
||||
enumerable: false,
|
||||
|
@ -560,17 +560,14 @@ export function genComment(comment: ASTText): string {
|
||||
function genSlot(el: ASTElement, state: CodegenState): string {
|
||||
const slotName = el.slotName || '"default"'
|
||||
const children = genChildren(el, state)
|
||||
let res = `_t(${slotName}${children ? `,${children}` : ''}`
|
||||
const attrs =
|
||||
el.attrs || el.dynamicAttrs
|
||||
? genProps(
|
||||
(el.attrs || []).concat(el.dynamicAttrs || []).map((attr) => ({
|
||||
let res = `_t(${slotName}${children ? `,function(){return ${children}}` : ''}`
|
||||
const attrs = el.attrs || el.dynamicAttrs
|
||||
? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(attr => ({
|
||||
// slot props are camelized
|
||||
name: camelize(attr.name),
|
||||
value: attr.value,
|
||||
dynamic: attr.dynamic,
|
||||
}))
|
||||
)
|
||||
dynamic: attr.dynamic
|
||||
})))
|
||||
: null
|
||||
const bind = el.attrsMap['v-bind']
|
||||
if ((attrs || bind) && !children) {
|
||||
|
@ -103,7 +103,7 @@ function checkIdentifier(
|
||||
if (typeof ident === 'string') {
|
||||
try {
|
||||
new Function(`var ${ident}=_`)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
warn(`invalid ${type} "${ident}" in expression: ${text.trim()}`, range)
|
||||
}
|
||||
}
|
||||
@ -117,7 +117,7 @@ function checkExpression(
|
||||
) {
|
||||
try {
|
||||
new Function(`return ${exp}`)
|
||||
} catch (e) {
|
||||
} catch (e:any) {
|
||||
const keywordMatch = exp
|
||||
.replace(stripStringRE, '')
|
||||
.match(prohibitedKeywordRE)
|
||||
@ -146,7 +146,7 @@ function checkFunctionParameterExpression(
|
||||
) {
|
||||
try {
|
||||
new Function(exp, '')
|
||||
} catch (e) {
|
||||
} catch (e:any) {
|
||||
warn(
|
||||
`invalid function parameter expression: ${e.message} in\n\n` +
|
||||
` ${exp}\n\n` +
|
||||
|
@ -12,7 +12,7 @@ type CompiledFunctionResult = {
|
||||
function createFunction(code, errors) {
|
||||
try {
|
||||
return new Function(code)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
errors.push({ err, code })
|
||||
return noop
|
||||
}
|
||||
@ -35,7 +35,7 @@ export function createCompileToFunctionFn(compile: Function): Function {
|
||||
// detect possible CSP restriction
|
||||
try {
|
||||
new Function('return 1')
|
||||
} catch (e) {
|
||||
} catch (e:any) {
|
||||
if (e.toString().match(/unsafe-eval|CSP/)) {
|
||||
warn(
|
||||
'It seems you are using the standalone build of Vue.js in an ' +
|
||||
|
@ -1,12 +1,21 @@
|
||||
import { isRegExp, remove } from 'shared/util'
|
||||
import { getFirstComponentChild } from 'core/vdom/helpers/index'
|
||||
import VNode from 'core/vdom/vnode'
|
||||
import type { VNodeComponentOptions } from 'typescript/vnode'
|
||||
/* @flow */
|
||||
|
||||
type VNodeCache = { [key: string]: VNode | null }
|
||||
import { isRegExp, remove } from "shared/util";
|
||||
import { getFirstComponentChild } from "core/vdom/helpers/index";
|
||||
import type VNode from "core/vdom/vnode";
|
||||
import type { VNodeComponentOptions } from "typescript/vnode";
|
||||
import type { Component } from "typescript/component";
|
||||
|
||||
type CacheEntry = {
|
||||
name?: string;
|
||||
tag?: string;
|
||||
componentInstance?: Component;
|
||||
};
|
||||
|
||||
type CacheEntryMap = Record<string, CacheEntry | null>;
|
||||
|
||||
function getComponentName(opts?: VNodeComponentOptions): string | null {
|
||||
return opts && (opts.Ctor.options.name || opts.tag)
|
||||
return opts && (opts.Ctor.options.name || opts.tag);
|
||||
}
|
||||
|
||||
function matches(
|
||||
@ -14,49 +23,52 @@ function matches(
|
||||
name: string
|
||||
): boolean {
|
||||
if (Array.isArray(pattern)) {
|
||||
return pattern.indexOf(name) > -1
|
||||
} else if (typeof pattern === 'string') {
|
||||
return pattern.split(',').indexOf(name) > -1
|
||||
return pattern.indexOf(name) > -1;
|
||||
} else if (typeof pattern === "string") {
|
||||
return pattern.split(",").indexOf(name) > -1;
|
||||
} else if (isRegExp(pattern)) {
|
||||
return pattern.test(name)
|
||||
return pattern.test(name);
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
function pruneCache(keepAliveInstance: any, filter: Function) {
|
||||
const { cache, keys, _vnode } = keepAliveInstance
|
||||
function pruneCache(
|
||||
keepAliveInstance: { cache: CacheEntryMap; keys: string[]; _vnode: VNode },
|
||||
filter: Function
|
||||
) {
|
||||
const { cache, keys, _vnode } = keepAliveInstance;
|
||||
for (const key in cache) {
|
||||
const cachedNode: VNode | null = cache[key]
|
||||
if (cachedNode) {
|
||||
const name = getComponentName(cachedNode.componentOptions)
|
||||
const entry = cache[key];
|
||||
if (entry) {
|
||||
const name = entry.name;
|
||||
if (name && !filter(name)) {
|
||||
pruneCacheEntry(cache, key, keys, _vnode)
|
||||
pruneCacheEntry(cache, key, keys, _vnode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pruneCacheEntry(
|
||||
cache: VNodeCache,
|
||||
cache: CacheEntryMap,
|
||||
key: string,
|
||||
keys: Array<string>,
|
||||
current?: VNode
|
||||
) {
|
||||
const cached = cache[key]
|
||||
if (cached && (!current || cached.tag !== current.tag)) {
|
||||
//@ts-expect-error has void type
|
||||
cached.componentInstance.$destroy()
|
||||
const entry = cache[key];
|
||||
if (entry && (!current || entry.tag !== current.tag)) {
|
||||
// @ts-expect-error can be undefined
|
||||
entry.componentInstance.$destroy();
|
||||
}
|
||||
cache[key] = null
|
||||
remove(keys, key)
|
||||
cache[key] = null;
|
||||
remove(keys, key);
|
||||
}
|
||||
|
||||
const patternTypes: Array<Function> = [String, RegExp, Array]
|
||||
const patternTypes: Array<Function> = [String, RegExp, Array];
|
||||
|
||||
// TODO use defineComponent
|
||||
// TODO defineComponent
|
||||
export default {
|
||||
name: 'keep-alive',
|
||||
name: "keep-alive",
|
||||
abstract: true,
|
||||
|
||||
props: {
|
||||
@ -65,68 +77,90 @@ export default {
|
||||
max: [String, Number],
|
||||
},
|
||||
|
||||
methods: {
|
||||
cacheVNode() {
|
||||
const { cache, keys, vnodeToCache, keyToCache } = this;
|
||||
if (vnodeToCache) {
|
||||
const { tag, componentInstance, componentOptions } = vnodeToCache;
|
||||
cache[keyToCache] = {
|
||||
name: getComponentName(componentOptions),
|
||||
tag,
|
||||
componentInstance,
|
||||
};
|
||||
keys.push(keyToCache);
|
||||
// prune oldest entry
|
||||
if (this.max && keys.length > parseInt(this.max)) {
|
||||
pruneCacheEntry(cache, keys[0], keys, this._vnode);
|
||||
}
|
||||
this.vnodeToCache = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.cache = Object.create(null)
|
||||
this.keys = []
|
||||
this.cache = Object.create(null);
|
||||
this.keys = [];
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
for (const key in this.cache) {
|
||||
pruneCacheEntry(this.cache, key, this.keys)
|
||||
pruneCacheEntry(this.cache, key, this.keys);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$watch('include', (val) => {
|
||||
pruneCache(this, (name) => matches(val, name))
|
||||
})
|
||||
this.$watch('exclude', (val) => {
|
||||
pruneCache(this, (name) => !matches(val, name))
|
||||
})
|
||||
this.cacheVNode();
|
||||
this.$watch("include", (val) => {
|
||||
pruneCache(this, (name) => matches(val, name));
|
||||
});
|
||||
this.$watch("exclude", (val) => {
|
||||
pruneCache(this, (name) => !matches(val, name));
|
||||
});
|
||||
},
|
||||
|
||||
updated() {
|
||||
this.cacheVNode();
|
||||
},
|
||||
|
||||
render() {
|
||||
const slot = this.$slots.default
|
||||
const vnode = getFirstComponentChild(slot)
|
||||
const componentOptions =
|
||||
vnode && vnode.componentOptions
|
||||
const slot = this.$slots.default;
|
||||
const vnode = getFirstComponentChild(slot);
|
||||
const componentOptions = vnode && vnode.componentOptions;
|
||||
if (componentOptions) {
|
||||
// check pattern
|
||||
const name = getComponentName(componentOptions)
|
||||
const { include, exclude } = this
|
||||
const name = getComponentName(componentOptions);
|
||||
const { include, exclude } = this;
|
||||
if (
|
||||
// not included
|
||||
(include && (!name || !matches(include, name))) ||
|
||||
// excluded
|
||||
(exclude && name && matches(exclude, name))
|
||||
) {
|
||||
return vnode
|
||||
return vnode;
|
||||
}
|
||||
|
||||
const { cache, keys } = this
|
||||
const { cache, keys } = this;
|
||||
const key =
|
||||
vnode!.key == null
|
||||
vnode.key == null
|
||||
? // same constructor may get registered as different local components
|
||||
// so cid alone is not enough (#3269)
|
||||
componentOptions.Ctor.cid +
|
||||
(componentOptions.tag ? `::${componentOptions.tag}` : '')
|
||||
: vnode!.key
|
||||
(componentOptions.tag ? `::${componentOptions.tag}` : "")
|
||||
: vnode.key;
|
||||
if (cache[key]) {
|
||||
vnode!.componentInstance = cache[key].componentInstance
|
||||
vnode.componentInstance = cache[key].componentInstance;
|
||||
// make current key freshest
|
||||
remove(keys, key)
|
||||
keys.push(key)
|
||||
remove(keys, key);
|
||||
keys.push(key);
|
||||
} else {
|
||||
cache[key] = vnode
|
||||
keys.push(key)
|
||||
// prune oldest entry
|
||||
if (this.max && keys.length > parseInt(this.max)) {
|
||||
pruneCacheEntry(cache, keys[0], keys, this._vnode)
|
||||
}
|
||||
// delay setting the cache until update
|
||||
this.vnodeToCache = vnode;
|
||||
this.keyToCache = key;
|
||||
}
|
||||
|
||||
vnode!.data!.keepAlive = true
|
||||
// @ts-expect-error can vnode.data can be undefined
|
||||
vnode.data.keepAlive = true;
|
||||
}
|
||||
return vnode || (slot && slot[0])
|
||||
return vnode || (slot && slot[0]);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -6,6 +6,8 @@ import { updateComponentListeners } from "./events";
|
||||
import { resolveSlots } from "./render-helpers/resolve-slots";
|
||||
import { toggleObserving } from "../observer/index";
|
||||
import { pushTarget, popTarget } from "../observer/dep";
|
||||
import type { Component } from "../../../typescript/component";
|
||||
import type { MountedComponentVNode } from "../../../typescript/vnode";
|
||||
|
||||
import {
|
||||
warn,
|
||||
@ -15,8 +17,6 @@ import {
|
||||
validateProp,
|
||||
invokeWithErrorHandling,
|
||||
} from "../util/index";
|
||||
import type { Component } from "typescript/component";
|
||||
import type { MountedComponentVNode } from "typescript/vnode";
|
||||
|
||||
export let activeInstance: any = null;
|
||||
export let isUpdatingChildComponent: boolean = false;
|
||||
@ -30,7 +30,7 @@ export function setActiveInstance(vm: Component) {
|
||||
}
|
||||
|
||||
export function initLifecycle(vm: Component) {
|
||||
const options: any = vm.$options;
|
||||
const options = vm.$options;
|
||||
|
||||
// locate first non-abstract parent
|
||||
let parent = options.parent;
|
||||
@ -122,7 +122,7 @@ export function lifecycleMixin(Vue: Component) {
|
||||
// call the last hook...
|
||||
vm._isDestroyed = true;
|
||||
// invoke destroy hooks on current rendered tree
|
||||
vm.__patch__(vm._vnode!, null);
|
||||
vm.__patch__(vm._vnode, null);
|
||||
// fire destroyed hook
|
||||
callHook(vm, "destroyed");
|
||||
// turn off all instance listeners.
|
||||
@ -133,7 +133,6 @@ export function lifecycleMixin(Vue: Component) {
|
||||
}
|
||||
// release circular reference (#6759)
|
||||
if (vm.$vnode) {
|
||||
// @ts-expect-error null is not undefined
|
||||
vm.$vnode.parent = null;
|
||||
}
|
||||
};
|
||||
@ -240,12 +239,13 @@ export function updateChildComponent(
|
||||
// check if there are dynamic scopedSlots (hand-written or compiled but with
|
||||
// dynamic slot names). Static scoped slots compiled from template has the
|
||||
// "$stable" marker.
|
||||
const newScopedSlots = parentVnode!.data.scopedSlots;
|
||||
const newScopedSlots = parentVnode.data.scopedSlots;
|
||||
const oldScopedSlots = vm.$scopedSlots;
|
||||
const hasDynamicScopedSlot = !!(
|
||||
(newScopedSlots && !newScopedSlots.$stable) ||
|
||||
(oldScopedSlots !== emptyObject && !oldScopedSlots.$stable) ||
|
||||
(newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key)
|
||||
(newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key) ||
|
||||
(!newScopedSlots && vm.$scopedSlots.$key)
|
||||
);
|
||||
|
||||
// Any static slot children from the parent may have changed during parent's
|
||||
@ -258,7 +258,6 @@ export function updateChildComponent(
|
||||
);
|
||||
|
||||
vm.$options._parentVnode = parentVnode;
|
||||
|
||||
vm.$vnode = parentVnode; // update vm's placeholder node without re-render
|
||||
|
||||
if (vm._vnode) {
|
||||
@ -270,7 +269,7 @@ export function updateChildComponent(
|
||||
// update $attrs and $listeners hash
|
||||
// these are also reactive so they may trigger child update if the child
|
||||
// used them during render
|
||||
vm.$attrs = parentVnode!.data.attrs || emptyObject;
|
||||
vm.$attrs = parentVnode.data.attrs || emptyObject;
|
||||
vm.$listeners = listeners || emptyObject;
|
||||
|
||||
// update props
|
||||
@ -296,7 +295,7 @@ export function updateChildComponent(
|
||||
|
||||
// resolve slots + force update if has children
|
||||
if (needsForceUpdate) {
|
||||
vm.$slots = resolveSlots(renderChildren, parentVnode!.context);
|
||||
vm.$slots = resolveSlots(renderChildren, parentVnode.context);
|
||||
vm.$forceUpdate();
|
||||
}
|
||||
|
||||
|
@ -30,4 +30,5 @@ export function checkKeyCodes(
|
||||
} else if (eventKeyName) {
|
||||
return hyphenate(eventKeyName) !== key
|
||||
}
|
||||
return eventKeyCode === undefined
|
||||
}
|
||||
|
@ -1,35 +1,43 @@
|
||||
import { extend, warn, isObject } from 'core/util/index'
|
||||
import VNode from 'core/vdom/vnode'
|
||||
import { extend, warn, isObject } from "core/util/index";
|
||||
import VNode from "core/vdom/vnode";
|
||||
|
||||
/**
|
||||
* Runtime helper for rendering <slot>
|
||||
*/
|
||||
export function renderSlot(
|
||||
name: string,
|
||||
fallback: Array<VNode> | null,
|
||||
fallbackRender: ((() => Array<VNode>) | Array<VNode>) | null,
|
||||
props: Record<string, any> | null,
|
||||
bindObject: object | null
|
||||
): Array<VNode> | null {
|
||||
const scopedSlotFn = this.$scopedSlots[name]
|
||||
let nodes
|
||||
const scopedSlotFn = this.$scopedSlots[name];
|
||||
let nodes;
|
||||
if (scopedSlotFn) {
|
||||
// scoped slot
|
||||
props = props || {}
|
||||
props = props || {};
|
||||
if (bindObject) {
|
||||
if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) {
|
||||
warn('slot v-bind without argument expects an Object', this)
|
||||
if (process.env.NODE_ENV !== "production" && !isObject(bindObject)) {
|
||||
warn("slot v-bind without argument expects an Object", this);
|
||||
}
|
||||
props = extend(extend({}, bindObject), props)
|
||||
props = extend(extend({}, bindObject), props);
|
||||
}
|
||||
nodes = scopedSlotFn(props) || fallback
|
||||
nodes =
|
||||
scopedSlotFn(props) ||
|
||||
(typeof fallbackRender === "function"
|
||||
? fallbackRender()
|
||||
: fallbackRender);
|
||||
} else {
|
||||
nodes = this.$slots[name] || fallback
|
||||
nodes =
|
||||
this.$slots[name] ||
|
||||
(typeof fallbackRender === "function"
|
||||
? fallbackRender()
|
||||
: fallbackRender);
|
||||
}
|
||||
|
||||
const target = props && props.slot
|
||||
const target = props && props.slot;
|
||||
if (target) {
|
||||
return this.$createElement('template', { slot: target }, nodes)
|
||||
return this.$createElement("template", { slot: target }, nodes);
|
||||
} else {
|
||||
return nodes
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ export function renderMixin(Vue: Component) {
|
||||
// when parent component is patched.
|
||||
currentRenderingInstance = vm
|
||||
vnode = render.call(vm._renderProxy, vm.$createElement)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
handleError(e, vm, `render`)
|
||||
// return error render result,
|
||||
// or previous vnode to prevent render error causing blank component
|
||||
@ -127,7 +127,7 @@ export function renderMixin(Vue: Component) {
|
||||
vm.$createElement,
|
||||
e
|
||||
)
|
||||
} catch (e) {
|
||||
} catch (e:any) {
|
||||
handleError(e, vm, `renderError`)
|
||||
vnode = vm._vnode
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
import config from '../config'
|
||||
import Watcher from '../observer/watcher'
|
||||
import Dep, { pushTarget, popTarget } from '../observer/dep'
|
||||
import { isUpdatingChildComponent } from './lifecycle'
|
||||
import config from "../config";
|
||||
import Watcher from "../observer/watcher";
|
||||
import Dep, { pushTarget, popTarget } from "../observer/dep";
|
||||
import { isUpdatingChildComponent } from "./lifecycle";
|
||||
|
||||
import {
|
||||
set,
|
||||
@ -10,7 +9,7 @@ import {
|
||||
observe,
|
||||
defineReactive,
|
||||
toggleObserving,
|
||||
} from '../observer/index'
|
||||
} from "../observer/index";
|
||||
|
||||
import {
|
||||
warn,
|
||||
@ -25,59 +24,60 @@ import {
|
||||
isPlainObject,
|
||||
isServerRendering,
|
||||
isReservedAttribute,
|
||||
} from '../util/index'
|
||||
import type { Component } from 'typescript/component'
|
||||
invokeWithErrorHandling,
|
||||
} from "../util/index";
|
||||
import type { Component } from "../../../typescript/component";
|
||||
|
||||
const sharedPropertyDefinition = {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: noop,
|
||||
set: noop,
|
||||
}
|
||||
};
|
||||
|
||||
export function proxy(target: Object, sourceKey: string, key: string) {
|
||||
sharedPropertyDefinition.get = function proxyGetter() {
|
||||
return this[sourceKey][key]
|
||||
}
|
||||
return this[sourceKey][key];
|
||||
};
|
||||
sharedPropertyDefinition.set = function proxySetter(val) {
|
||||
this[sourceKey][key] = val
|
||||
}
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition)
|
||||
this[sourceKey][key] = val;
|
||||
};
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition);
|
||||
}
|
||||
|
||||
export function initState(vm: Component) {
|
||||
vm._watchers = []
|
||||
const opts = vm.$options
|
||||
if (opts.props) initProps(vm, opts.props)
|
||||
if (opts.methods) initMethods(vm, opts.methods)
|
||||
vm._watchers = [];
|
||||
const opts = vm.$options;
|
||||
if (opts.props) initProps(vm, opts.props);
|
||||
if (opts.methods) initMethods(vm, opts.methods);
|
||||
if (opts.data) {
|
||||
initData(vm)
|
||||
initData(vm);
|
||||
} else {
|
||||
observe((vm._data = {}), true /* asRootData */)
|
||||
observe((vm._data = {}), true /* asRootData */);
|
||||
}
|
||||
if (opts.computed) initComputed(vm, opts.computed)
|
||||
if (opts.computed) initComputed(vm, opts.computed);
|
||||
if (opts.watch && opts.watch !== nativeWatch) {
|
||||
initWatch(vm, opts.watch)
|
||||
initWatch(vm, opts.watch);
|
||||
}
|
||||
}
|
||||
|
||||
function initProps(vm: Component, propsOptions: Object) {
|
||||
const propsData = vm.$options.propsData || {}
|
||||
const props = (vm._props = {})
|
||||
const propsData = vm.$options.propsData || {};
|
||||
const props = (vm._props = {});
|
||||
// cache prop keys so that future props updates can iterate using Array
|
||||
// instead of dynamic object key enumeration.
|
||||
const keys: string[] = (vm.$options._propKeys = [])
|
||||
const isRoot = !vm.$parent
|
||||
const keys: string[] = (vm.$options._propKeys = []);
|
||||
const isRoot = !vm.$parent;
|
||||
// root instance props should be converted
|
||||
if (!isRoot) {
|
||||
toggleObserving(false)
|
||||
toggleObserving(false);
|
||||
}
|
||||
for (const key in propsOptions) {
|
||||
keys.push(key)
|
||||
const value = validateProp(key, propsOptions, propsData, vm)
|
||||
keys.push(key);
|
||||
const value = validateProp(key, propsOptions, propsData, vm);
|
||||
/* istanbul ignore else */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const hyphenatedKey = hyphenate(key)
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const hyphenatedKey = hyphenate(key);
|
||||
if (
|
||||
isReservedAttribute(hyphenatedKey) ||
|
||||
config.isReservedAttr(hyphenatedKey)
|
||||
@ -85,7 +85,7 @@ function initProps(vm: Component, propsOptions: Object) {
|
||||
warn(
|
||||
`"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
defineReactive(props, key, value, () => {
|
||||
if (!isRoot && !isUpdatingChildComponent) {
|
||||
@ -95,87 +95,90 @@ function initProps(vm: Component, propsOptions: Object) {
|
||||
`Instead, use a data or computed property based on the prop's ` +
|
||||
`value. Prop being mutated: "${key}"`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
defineReactive(props, key, value)
|
||||
defineReactive(props, key, value);
|
||||
}
|
||||
// static props are already proxied on the component's prototype
|
||||
// during Vue.extend(). We only need to proxy props defined at
|
||||
// instantiation here.
|
||||
if (!(key in vm)) {
|
||||
proxy(vm, `_props`, key)
|
||||
proxy(vm, `_props`, key);
|
||||
}
|
||||
}
|
||||
toggleObserving(true)
|
||||
toggleObserving(true);
|
||||
}
|
||||
|
||||
function initData(vm: Component) {
|
||||
let data: any = vm.$options.data
|
||||
data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
|
||||
let data: any = vm.$options.data;
|
||||
data = vm._data = typeof data === "function" ? getData(data, vm) : data || {};
|
||||
if (!isPlainObject(data)) {
|
||||
data = {}
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
data = {};
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
warn(
|
||||
'data functions should return an object:\n' +
|
||||
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
|
||||
"data functions should return an object:\n" +
|
||||
"https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function",
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
// proxy data on instance
|
||||
const keys = Object.keys(data)
|
||||
const props = vm.$options.props
|
||||
const methods = vm.$options.methods
|
||||
let i = keys.length
|
||||
const keys = Object.keys(data);
|
||||
const props = vm.$options.props;
|
||||
const methods = vm.$options.methods;
|
||||
let i = keys.length;
|
||||
while (i--) {
|
||||
const key = keys[i]
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const key = keys[i];
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (methods && hasOwn(methods, key)) {
|
||||
warn(`Method "${key}" has already been defined as a data property.`, vm)
|
||||
warn(
|
||||
`Method "${key}" has already been defined as a data property.`,
|
||||
vm
|
||||
);
|
||||
}
|
||||
}
|
||||
if (props && hasOwn(props, key)) {
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
warn(
|
||||
`The data property "${key}" is already declared as a prop. ` +
|
||||
`Use prop default value instead.`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
} else if (!isReserved(key)) {
|
||||
proxy(vm, `_data`, key)
|
||||
proxy(vm, `_data`, key);
|
||||
}
|
||||
}
|
||||
// observe data
|
||||
observe(data, true /* asRootData */)
|
||||
observe(data, true /* asRootData */);
|
||||
}
|
||||
|
||||
export function getData(data: Function, vm: Component): any {
|
||||
// #7573 disable dep collection when invoking data getters
|
||||
pushTarget()
|
||||
pushTarget();
|
||||
try {
|
||||
return data.call(vm, vm)
|
||||
} catch (e) {
|
||||
handleError(e, vm, `data()`)
|
||||
return {}
|
||||
return data.call(vm, vm);
|
||||
} catch (e: any) {
|
||||
handleError(e, vm, `data()`);
|
||||
return {};
|
||||
} finally {
|
||||
popTarget()
|
||||
popTarget();
|
||||
}
|
||||
}
|
||||
|
||||
const computedWatcherOptions = { lazy: true }
|
||||
const computedWatcherOptions = { lazy: true };
|
||||
|
||||
function initComputed(vm: Component, computed: Object) {
|
||||
// $flow-disable-line
|
||||
const watchers = (vm._computedWatchers = Object.create(null))
|
||||
const watchers = (vm._computedWatchers = Object.create(null));
|
||||
// computed properties are just getters during SSR
|
||||
const isSSR = isServerRendering()
|
||||
const isSSR = isServerRendering();
|
||||
|
||||
for (const key in computed) {
|
||||
const userDef = computed[key]
|
||||
const getter = typeof userDef === 'function' ? userDef : userDef.get
|
||||
if (process.env.NODE_ENV !== 'production' && getter == null) {
|
||||
warn(`Getter is missing for computed property "${key}".`, vm)
|
||||
const userDef = computed[key];
|
||||
const getter = typeof userDef === "function" ? userDef : userDef.get;
|
||||
if (process.env.NODE_ENV !== "production" && getter == null) {
|
||||
warn(`Getter is missing for computed property "${key}".`, vm);
|
||||
}
|
||||
|
||||
if (!isSSR) {
|
||||
@ -185,19 +188,27 @@ function initComputed(vm: Component, computed: Object) {
|
||||
getter || noop,
|
||||
noop,
|
||||
computedWatcherOptions
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// component-defined computed properties are already defined on the
|
||||
// component prototype. We only need to define computed properties defined
|
||||
// at instantiation here.
|
||||
if (!(key in vm)) {
|
||||
defineComputed(vm, key, userDef)
|
||||
} else if (process.env.NODE_ENV !== 'production') {
|
||||
defineComputed(vm, key, userDef);
|
||||
} else if (process.env.NODE_ENV !== "production") {
|
||||
if (key in vm.$data) {
|
||||
warn(`The computed property "${key}" is already defined in data.`, vm)
|
||||
warn(`The computed property "${key}" is already defined in data.`, vm);
|
||||
} else if (vm.$options.props && key in vm.$options.props) {
|
||||
warn(`The computed property "${key}" is already defined as a prop.`, vm)
|
||||
warn(
|
||||
`The computed property "${key}" is already defined as a prop.`,
|
||||
vm
|
||||
);
|
||||
} else if (vm.$options.methods && key in vm.$options.methods) {
|
||||
warn(
|
||||
`The computed property "${key}" is already defined as a method.`,
|
||||
vm
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -208,91 +219,92 @@ export function defineComputed(
|
||||
key: string,
|
||||
userDef: Record<string, any> | Function
|
||||
) {
|
||||
const shouldCache = !isServerRendering()
|
||||
if (typeof userDef === 'function') {
|
||||
const shouldCache = !isServerRendering();
|
||||
if (typeof userDef === "function") {
|
||||
sharedPropertyDefinition.get = shouldCache
|
||||
? createComputedGetter(key)
|
||||
: createGetterInvoker(userDef)
|
||||
sharedPropertyDefinition.set = noop
|
||||
: createGetterInvoker(userDef);
|
||||
sharedPropertyDefinition.set = noop;
|
||||
} else {
|
||||
sharedPropertyDefinition.get = userDef.get
|
||||
? shouldCache && userDef.cache !== false
|
||||
? createComputedGetter(key)
|
||||
: createGetterInvoker(userDef.get)
|
||||
: noop
|
||||
sharedPropertyDefinition.set = userDef.set || noop
|
||||
: noop;
|
||||
sharedPropertyDefinition.set = userDef.set || noop;
|
||||
}
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
sharedPropertyDefinition.set === noop
|
||||
) {
|
||||
sharedPropertyDefinition.set = function () {
|
||||
warn(
|
||||
`Computed property "${key}" was assigned to but it has no setter.`,
|
||||
this
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition)
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition);
|
||||
}
|
||||
|
||||
function createComputedGetter(key) {
|
||||
return function computedGetter() {
|
||||
const watcher = this._computedWatchers && this._computedWatchers[key]
|
||||
const watcher = this._computedWatchers && this._computedWatchers[key];
|
||||
if (watcher) {
|
||||
if (watcher.dirty) {
|
||||
watcher.evaluate()
|
||||
watcher.evaluate();
|
||||
}
|
||||
if (Dep.target) {
|
||||
watcher.depend()
|
||||
}
|
||||
return watcher.value
|
||||
watcher.depend();
|
||||
}
|
||||
return watcher.value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createGetterInvoker(fn) {
|
||||
return function computedGetter() {
|
||||
return fn.call(this, this)
|
||||
}
|
||||
return fn.call(this, this);
|
||||
};
|
||||
}
|
||||
|
||||
function initMethods(vm: Component, methods: Object) {
|
||||
const props = vm.$options.props
|
||||
const props = vm.$options.props;
|
||||
for (const key in methods) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (typeof methods[key] !== 'function') {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (typeof methods[key] !== "function") {
|
||||
warn(
|
||||
`Method "${key}" has type "${typeof methods[
|
||||
key
|
||||
]}" in the component definition. ` +
|
||||
`Did you reference the function correctly?`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
if (props && hasOwn(props, key)) {
|
||||
warn(`Method "${key}" has already been defined as a prop.`, vm)
|
||||
warn(`Method "${key}" has already been defined as a prop.`, vm);
|
||||
}
|
||||
if (key in vm && isReserved(key)) {
|
||||
warn(
|
||||
`Method "${key}" conflicts with an existing Vue instance method. ` +
|
||||
`Avoid defining component methods that start with _ or $.`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
|
||||
vm[key] =
|
||||
typeof methods[key] !== "function" ? noop : bind(methods[key], vm);
|
||||
}
|
||||
}
|
||||
|
||||
function initWatch(vm: Component, watch: Object) {
|
||||
for (const key in watch) {
|
||||
const handler = watch[key]
|
||||
const handler = watch[key];
|
||||
if (Array.isArray(handler)) {
|
||||
for (let i = 0; i < handler.length; i++) {
|
||||
createWatcher(vm, key, handler[i])
|
||||
createWatcher(vm, key, handler[i]);
|
||||
}
|
||||
} else {
|
||||
createWatcher(vm, key, handler)
|
||||
createWatcher(vm, key, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -304,72 +316,65 @@ function createWatcher(
|
||||
options?: Object
|
||||
) {
|
||||
if (isPlainObject(handler)) {
|
||||
options = handler
|
||||
handler = handler.handler
|
||||
options = handler;
|
||||
handler = handler.handler;
|
||||
}
|
||||
if (typeof handler === 'string') {
|
||||
handler = vm[handler]
|
||||
if (typeof handler === "string") {
|
||||
handler = vm[handler];
|
||||
}
|
||||
return vm.$watch(expOrFn, handler, options)
|
||||
return vm.$watch(expOrFn, handler, options);
|
||||
}
|
||||
|
||||
export function stateMixin(Vue: Component) {
|
||||
// flow somehow has problems with directly declared definition object
|
||||
// when using Object.defineProperty, so we have to procedurally build up
|
||||
// the object here.
|
||||
const dataDef:any = {}
|
||||
const dataDef: any = {};
|
||||
dataDef.get = function () {
|
||||
return this._data
|
||||
}
|
||||
const propsDef: any = {}
|
||||
return this._data;
|
||||
};
|
||||
const propsDef: any = {};
|
||||
propsDef.get = function () {
|
||||
return this._props
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
return this._props;
|
||||
};
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
dataDef.set = function () {
|
||||
warn(
|
||||
'Avoid replacing instance root $data. ' +
|
||||
'Use nested data properties instead.',
|
||||
"Avoid replacing instance root $data. " +
|
||||
"Use nested data properties instead.",
|
||||
this
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
propsDef.set = function () {
|
||||
warn(`$props is readonly.`, this)
|
||||
warn(`$props is readonly.`, this);
|
||||
};
|
||||
}
|
||||
}
|
||||
Object.defineProperty(Vue.prototype, '$data', dataDef)
|
||||
Object.defineProperty(Vue.prototype, '$props', propsDef)
|
||||
Object.defineProperty(Vue.prototype, "$data", dataDef);
|
||||
Object.defineProperty(Vue.prototype, "$props", propsDef);
|
||||
|
||||
Vue.prototype.$set = set
|
||||
Vue.prototype.$delete = del
|
||||
Vue.prototype.$set = set;
|
||||
Vue.prototype.$delete = del;
|
||||
|
||||
Vue.prototype.$watch = function (
|
||||
expOrFn: string | Function,
|
||||
cb: any,
|
||||
options?: Record<string,any>
|
||||
options?: Record<string, any>
|
||||
): Function {
|
||||
const vm: Component = this
|
||||
const vm: Component = this;
|
||||
if (isPlainObject(cb)) {
|
||||
return createWatcher(vm, expOrFn, cb, options)
|
||||
return createWatcher(vm, expOrFn, cb, options);
|
||||
}
|
||||
options = options || {}
|
||||
options.user = true
|
||||
const watcher = new Watcher(vm, expOrFn, cb, options)
|
||||
options = options || {};
|
||||
options.user = true;
|
||||
const watcher = new Watcher(vm, expOrFn, cb, options);
|
||||
if (options.immediate) {
|
||||
pushTarget()
|
||||
try {
|
||||
cb.call(vm, watcher.value)
|
||||
} catch (error) {
|
||||
handleError(
|
||||
error,
|
||||
vm,
|
||||
`callback for immediate watcher "${watcher.expression}"`
|
||||
)
|
||||
}
|
||||
popTarget()
|
||||
const info = `callback for immediate watcher "${watcher.expression}"`;
|
||||
pushTarget();
|
||||
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info);
|
||||
popTarget();
|
||||
}
|
||||
return function unwatchFn() {
|
||||
watcher.teardown()
|
||||
}
|
||||
}
|
||||
watcher.teardown();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
parsePath,
|
||||
_Set as Set,
|
||||
handleError,
|
||||
noop,
|
||||
invokeWithErrorHandling,
|
||||
noop
|
||||
} from '../util/index'
|
||||
|
||||
import { traverse } from './traverse'
|
||||
@ -78,8 +79,9 @@ export default class Watcher {
|
||||
this.newDeps = []
|
||||
this.depIds = new Set()
|
||||
this.newDepIds = new Set()
|
||||
this.expression =
|
||||
process.env.NODE_ENV !== 'production' ? expOrFn.toString() : ''
|
||||
this.expression = process.env.NODE_ENV !== 'production'
|
||||
? expOrFn.toString()
|
||||
: ''
|
||||
// parse expression for getter
|
||||
if (typeof expOrFn === 'function') {
|
||||
this.getter = expOrFn
|
||||
@ -87,8 +89,7 @@ export default class Watcher {
|
||||
this.getter = parsePath(expOrFn)
|
||||
if (!this.getter) {
|
||||
this.getter = noop
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
warn(
|
||||
process.env.NODE_ENV !== 'production' && warn(
|
||||
`Failed watching path: "${expOrFn}" ` +
|
||||
'Watcher only accepts simple dot-delimited paths. ' +
|
||||
'For full control, use a function instead.',
|
||||
@ -96,7 +97,9 @@ export default class Watcher {
|
||||
)
|
||||
}
|
||||
}
|
||||
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
|
||||
try {
|
||||
value = this.getter.call(vm, vm)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (this.user) {
|
||||
handleError(e, vm, `getter for watcher "${this.expression}"`)
|
||||
} else {
|
||||
@ -195,11 +198,8 @@ export default class Watcher {
|
||||
const oldValue = this.value
|
||||
this.value = value
|
||||
if (this.user) {
|
||||
try {
|
||||
this.cb.call(this.vm, value, oldValue)
|
||||
} catch (e) {
|
||||
handleError(e, this.vm, `callback for watcher "${this.expression}"`)
|
||||
}
|
||||
const info = `callback for watcher "${this.expression}"`
|
||||
invokeWithErrorHandling(this.cb, this.vm, [value, oldValue], this.vm, info)
|
||||
} else {
|
||||
this.cb.call(this.vm, value, oldValue)
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ if (inBrowser) {
|
||||
},
|
||||
} as object) // https://github.com/facebook/flow/issues/285
|
||||
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
|
||||
@ -75,10 +75,8 @@ let _Set // $flow-disable-line
|
||||
} else {
|
||||
// a non-standard Set polyfill that only works with primitive keys.
|
||||
_Set = class Set implements SimpleSet {
|
||||
set: Object
|
||||
constructor() {
|
||||
this.set = Object.create(null)
|
||||
}
|
||||
set: Record<string, boolean> = Object.create(null)
|
||||
|
||||
has(key: string | number) {
|
||||
return this.set[key] === true
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ export function handleError(err: Error, vm: any, info: string) {
|
||||
try {
|
||||
const capture = hooks[i].call(cur, err, vm, info) === false
|
||||
if (capture) return
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
globalHandleError(e, cur, 'errorCaptured hook')
|
||||
}
|
||||
}
|
||||
@ -47,7 +47,7 @@ export function invokeWithErrorHandling(
|
||||
// avoid catch triggering multiple times when nested calls
|
||||
res._handled = true
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
handleError(e, vm, info)
|
||||
}
|
||||
return res
|
||||
@ -57,7 +57,7 @@ function globalHandleError(err, vm, info) {
|
||||
if (config.errorHandler) {
|
||||
try {
|
||||
return config.errorHandler.call(null, err, vm, info)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
// if the user intentionally throws the original error in the handler,
|
||||
// do not log it twice
|
||||
if (e !== err) {
|
||||
|
@ -91,7 +91,8 @@ export function nextTick(cb?: Function, ctx?: Object) {
|
||||
if (cb) {
|
||||
try {
|
||||
cb.call(ctx)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
// @ts-expect-error should it be any?
|
||||
handleError(e, ctx, 'nextTick')
|
||||
}
|
||||
} else if (_resolve) {
|
||||
|
@ -175,7 +175,7 @@ function assertType(
|
||||
} else {
|
||||
try {
|
||||
valid = value instanceof type
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
warn('Invalid prop type: "' + String(type) + '" is not a constructor', vm)
|
||||
valid = false
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
|
||||
import { def } from 'core/util/lang'
|
||||
import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
|
||||
import { emptyObject } from 'shared/util'
|
||||
import VNode from '../vnode'
|
||||
import { def } from "core/util/lang";
|
||||
import { normalizeChildren } from "core/vdom/helpers/normalize-children";
|
||||
import { emptyObject } from "shared/util";
|
||||
import { isAsyncPlaceholder } from "./is-async-placeholder";
|
||||
import type VNode from "../vnode";
|
||||
|
||||
export function normalizeScopedSlots(
|
||||
slots: { [key: string]: Function } | void,
|
||||
normalSlots: { [key: string]: Array<VNode> },
|
||||
prevSlots?: { [key: string]: Function } | void
|
||||
): any {
|
||||
let res
|
||||
const hasNormalSlots = Object.keys(normalSlots).length > 0
|
||||
const isStable = slots ? !!slots.$stable : !hasNormalSlots
|
||||
const key = slots && slots.$key
|
||||
let res;
|
||||
const hasNormalSlots = Object.keys(normalSlots).length > 0;
|
||||
const isStable = slots ? !!slots.$stable : !hasNormalSlots;
|
||||
const key = slots && slots.$key;
|
||||
if (!slots) {
|
||||
res = {}
|
||||
res = {};
|
||||
} else if (slots._normalized) {
|
||||
// fast path 1: child component re-render only, parent did not change
|
||||
return slots._normalized
|
||||
return slots._normalized;
|
||||
} else if (
|
||||
isStable &&
|
||||
prevSlots &&
|
||||
@ -28,43 +28,46 @@ export function normalizeScopedSlots(
|
||||
) {
|
||||
// fast path 2: stable scoped slots w/ no normal slots to proxy,
|
||||
// only need to normalize once
|
||||
return prevSlots
|
||||
return prevSlots;
|
||||
} else {
|
||||
res = {}
|
||||
res = {};
|
||||
for (const key in slots) {
|
||||
if (slots[key] && key[0] !== '$') {
|
||||
res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
|
||||
if (slots[key] && key[0] !== "$") {
|
||||
res[key] = normalizeScopedSlot(normalSlots, key, slots[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// expose normal slots on scopedSlots
|
||||
for (const key in normalSlots) {
|
||||
if (!(key in res)) {
|
||||
res[key] = proxyNormalSlot(normalSlots, key)
|
||||
res[key] = proxyNormalSlot(normalSlots, key);
|
||||
}
|
||||
}
|
||||
// avoriaz seems to mock a non-extensible $scopedSlots object
|
||||
// and when that is passed down this would cause an error
|
||||
if (slots && Object.isExtensible(slots)) {
|
||||
slots._normalized = res
|
||||
slots._normalized = res;
|
||||
}
|
||||
def(res, '$stable', isStable)
|
||||
def(res, '$key', key)
|
||||
def(res, '$hasNormal', hasNormalSlots)
|
||||
return res
|
||||
def(res, "$stable", isStable);
|
||||
def(res, "$key", key);
|
||||
def(res, "$hasNormal", hasNormalSlots);
|
||||
return res;
|
||||
}
|
||||
|
||||
function normalizeScopedSlot(normalSlots, key, fn) {
|
||||
const normalized = function () {
|
||||
let res = arguments.length ? fn.apply(null, arguments) : fn({})
|
||||
let res = arguments.length ? fn.apply(null, arguments) : fn({});
|
||||
res =
|
||||
res && typeof res === 'object' && !Array.isArray(res)
|
||||
res && typeof res === "object" && !Array.isArray(res)
|
||||
? [res] // single vnode
|
||||
: normalizeChildren(res)
|
||||
return res && (res.length === 0 || (res.length === 1 && res[0].isComment)) // #9658
|
||||
: normalizeChildren(res);
|
||||
const vnode: VNode | null = res && res[0];
|
||||
return res &&
|
||||
(!vnode ||
|
||||
(res.length === 1 && vnode.isComment && !isAsyncPlaceholder(vnode))) // #9658, #10391
|
||||
? undefined
|
||||
: res
|
||||
}
|
||||
: res;
|
||||
};
|
||||
// this is a slot using the new v-slot syntax without scope. although it is
|
||||
// compiled as a scoped slot, render fn users would expect it to be present
|
||||
// on this.$slots because the usage is semantically a normal slot.
|
||||
@ -73,11 +76,11 @@ function normalizeScopedSlot(normalSlots, key, fn) {
|
||||
get: normalized,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
})
|
||||
});
|
||||
}
|
||||
return normalized
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function proxyNormalSlot(slots, key) {
|
||||
return () => slots[key]
|
||||
return () => slots[key];
|
||||
}
|
||||
|
@ -120,7 +120,8 @@ function callHook(dir, hook, vnode, oldVnode, isDestroy?: any) {
|
||||
if (fn) {
|
||||
try {
|
||||
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`)
|
||||
}
|
||||
}
|
||||
|
@ -35,13 +35,17 @@ const hooks = ['create', 'activate', 'update', 'remove', 'destroy']
|
||||
function sameVnode(a, b) {
|
||||
return (
|
||||
a.key === b.key &&
|
||||
((a.tag === b.tag &&
|
||||
a.asyncFactory === b.asyncFactory && (
|
||||
(
|
||||
a.tag === b.tag &&
|
||||
a.isComment === b.isComment &&
|
||||
isDef(a.data) === isDef(b.data) &&
|
||||
sameInputType(a, b)) ||
|
||||
(isTrue(a.isAsyncPlaceholder) &&
|
||||
a.asyncFactory === b.asyncFactory &&
|
||||
isUndef(b.asyncFactory.error)))
|
||||
sameInputType(a, b)
|
||||
) || (
|
||||
isTrue(a.isAsyncPlaceholder) &&
|
||||
isUndef(b.asyncFactory.error)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ export default class VNode {
|
||||
key: string | number | undefined;
|
||||
componentOptions?: VNodeComponentOptions;
|
||||
componentInstance?: Component; // component instance
|
||||
parent: VNode | undefined; // component placeholder node
|
||||
parent: VNode | undefined | null; // component placeholder node
|
||||
|
||||
// strictly internal
|
||||
raw: boolean; // contains raw HTML? (server only)
|
||||
|
@ -18,7 +18,7 @@ function transformNode(el: ASTElement, options: CompilerOptions) {
|
||||
}
|
||||
}
|
||||
if (staticClass) {
|
||||
el.staticClass = JSON.stringify(staticClass)
|
||||
el.staticClass = JSON.stringify(staticClass.replace(/\s+/g, ' ').trim())
|
||||
}
|
||||
const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
|
||||
if (classBinding) {
|
||||
|
@ -74,7 +74,7 @@ function updateDOMProps(oldVnode: VNodeWithData, vnode: VNodeWithData) {
|
||||
// e.g. `value` on <progress> w/ non-finite value
|
||||
try {
|
||||
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
|
||||
try {
|
||||
notInFocus = document.activeElement !== elm
|
||||
} catch (e) {}
|
||||
} catch (e: any) {}
|
||||
return notInFocus && elm.value !== checkVal
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
CHECKBOX_RADIO_TOKEN,
|
||||
} from 'web/compiler/directives/model'
|
||||
import { currentFlushTimestamp } from 'core/observer/scheduler'
|
||||
import { emptyNode } from 'core/vdom/patch'
|
||||
import type { VNodeWithData } from 'typescript/vnode'
|
||||
|
||||
// normalize v-model event tokens that can only be determined at runtime.
|
||||
@ -111,7 +112,9 @@ function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
|
||||
}
|
||||
const on = vnode.data.on || {}
|
||||
const oldOn = oldVnode.data.on || {}
|
||||
target = vnode.elm
|
||||
// vnode is empty when removing all listeners,
|
||||
// and use old vnode dom element
|
||||
target = vnode.elm || oldVnode.elm
|
||||
normalizeEvents(on)
|
||||
updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)
|
||||
target = undefined
|
||||
@ -120,4 +123,6 @@ function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
|
||||
export default {
|
||||
create: updateDOMListeners,
|
||||
update: updateDOMListeners,
|
||||
// @ts-expect-error emptyNode has actually data
|
||||
destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode)
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ if (hasTransition) {
|
||||
/* istanbul ignore if */
|
||||
if (
|
||||
window.ontransitionend === undefined &&
|
||||
// @ts-expect-error
|
||||
window.onwebkittransitionend !== undefined
|
||||
) {
|
||||
transitionProp = 'WebkitTransition'
|
||||
@ -53,7 +52,6 @@ if (hasTransition) {
|
||||
}
|
||||
if (
|
||||
window.onanimationend === undefined &&
|
||||
// @ts-expect-error
|
||||
window.onwebkitanimationend !== undefined
|
||||
) {
|
||||
animationProp = 'WebkitAnimation'
|
||||
|
@ -13,6 +13,7 @@ export function genClassForVnode(vnode: VNodeWithData): string {
|
||||
data = mergeClassData(childNode.data, data)
|
||||
}
|
||||
}
|
||||
// @ts-expect-error parentNode.parent not VNodeWithData
|
||||
while (isDef((parentNode = parentNode.parent))) {
|
||||
if (parentNode && parentNode.data) {
|
||||
data = mergeClassData(data, parentNode.data)
|
||||
|
@ -62,6 +62,7 @@ export function getStyle(vnode: VNodeWithData, checkChild: boolean): Object {
|
||||
}
|
||||
|
||||
let parentNode: VNodeWithData | VNode | undefined = vnode
|
||||
// @ts-expect-error parentNode.parent not VNodeWithData
|
||||
while ((parentNode = parentNode.parent)) {
|
||||
if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) {
|
||||
extend(res, styleData)
|
||||
|
@ -25,11 +25,11 @@ export function createInstanceContext(
|
||||
instanceId,
|
||||
config: weex.config,
|
||||
document: weex.document,
|
||||
data,
|
||||
data
|
||||
})
|
||||
|
||||
// Each instance has a independent `Vue` module instance
|
||||
const Vue = (instance.Vue = createVueModuleInstance(instanceId, weex))
|
||||
// Each instance has an independent `Vue` module instance
|
||||
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
|
||||
|
||||
// DEPRECATED
|
||||
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)
|
||||
@ -50,7 +50,7 @@ export function destroyInstance(instanceId: string): void {
|
||||
try {
|
||||
instance.app!.$destroy()
|
||||
instance.document.destroy()
|
||||
} catch (e) {}
|
||||
} catch (e: any) {}
|
||||
//@ts-expect-error
|
||||
delete instance.document
|
||||
delete instance.app
|
||||
@ -137,7 +137,7 @@ function createVueModuleInstance(instanceId: string, weex: Weex): GlobalAPI {
|
||||
try {
|
||||
// Send "createFinish" signal to native.
|
||||
weex.document.taskCenter.send('dom', { action: 'createFinish' }, [])
|
||||
} catch (e) {}
|
||||
} catch (e: any) {}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -22,7 +22,7 @@ export function renderRecyclableComponentTemplate(
|
||||
if (render) {
|
||||
try {
|
||||
return render.call(vm)
|
||||
} catch (err) {
|
||||
} catch (err:any) {
|
||||
handleError(err, vm, `@render`)
|
||||
}
|
||||
} else {
|
||||
|
@ -44,7 +44,7 @@ export function generateBinding(exp?: string): any {
|
||||
let ast: acorn.Node| null = null;
|
||||
try {
|
||||
ast = acorn.parse(`(${exp})`, {ecmaVersion: 5});
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
// warn(`Failed to parse the expression: "${exp}"`)
|
||||
return "";
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ export function createBundleRendererCreator(
|
||||
try {
|
||||
// @ts-expect-error
|
||||
bundle = JSON.parse(bundle)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
throw new Error(`Invalid JSON bundle file: ${bundle}`)
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ export function createBasicRenderer({
|
||||
render(component, write, context, () => {
|
||||
done(null, result)
|
||||
})
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
done(e)
|
||||
}
|
||||
}
|
||||
|
@ -106,14 +106,14 @@ export function createRenderer({
|
||||
} else {
|
||||
cb(null, res)
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
cb(e)
|
||||
}
|
||||
} else {
|
||||
cb(null, result)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
cb(e)
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ export default class RenderStream extends Readable {
|
||||
tryRender() {
|
||||
try {
|
||||
this.render(this.write, this.end)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
this.emit('error', e)
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ export default class RenderStream extends Readable {
|
||||
tryNext() {
|
||||
try {
|
||||
this.next()
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
this.emit('error', e)
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ function waitForServerPrefetch(vm, resolve, reject) {
|
||||
}
|
||||
Promise.all(promises).then(resolve).catch(reject)
|
||||
return
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
reject(e)
|
||||
}
|
||||
}
|
||||
@ -264,7 +264,7 @@ function renderAsyncComponent(node, isRoot, context) {
|
||||
let res
|
||||
try {
|
||||
res = factory(resolve, reject)
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
reject(e)
|
||||
}
|
||||
if (res) {
|
||||
|
67
src/server/webpack-plugin/client.js
Normal file
67
src/server/webpack-plugin/client.js
Normal 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()
|
||||
})
|
||||
}
|
||||
}
|
@ -1,34 +1,36 @@
|
||||
const hash = require('hash-sum')
|
||||
const uniq = require('lodash.uniq')
|
||||
import { isJS, isCSS, onEmit } from './util'
|
||||
const hash = require("hash-sum");
|
||||
const uniq = require("lodash.uniq");
|
||||
import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from "./util";
|
||||
|
||||
export default class VueSSRClientPlugin {
|
||||
constructor(options = {}) {
|
||||
//@ts-expect-error
|
||||
//@ts-expect-error no type on options
|
||||
this.options = Object.assign(
|
||||
{
|
||||
filename: 'vue-ssr-client-manifest.json',
|
||||
filename: "vue-ssr-client-manifest.json",
|
||||
},
|
||||
options
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
onEmit(compiler, 'vue-client-plugin', (compilation, cb) => {
|
||||
const stats = compilation.getStats().toJson()
|
||||
const stage = "PROCESS_ASSETS_STAGE_ADDITIONAL";
|
||||
onEmit(compiler, "vue-client-plugin", stage, (compilation, cb) => {
|
||||
const stats = compilation.getStats().toJson();
|
||||
|
||||
const allFiles = uniq(stats.assets.map((a) => a.name))
|
||||
const allFiles = uniq(stats.assets.map((a) => a.name));
|
||||
|
||||
const initialFiles = uniq(
|
||||
Object.keys(stats.entrypoints)
|
||||
.map((name) => stats.entrypoints[name].assets)
|
||||
.reduce((assets, all) => all.concat(assets), [])
|
||||
.map(getAssetName)
|
||||
.filter((file) => isJS(file) || isCSS(file))
|
||||
)
|
||||
);
|
||||
|
||||
const asyncFiles = allFiles
|
||||
.filter((file) => isJS(file) || isCSS(file))
|
||||
.filter((file) => initialFiles.indexOf(file) < 0)
|
||||
.filter((file) => initialFiles.indexOf(file) < 0);
|
||||
|
||||
const manifest = {
|
||||
publicPath: stats.publicPath,
|
||||
@ -38,38 +40,37 @@ export default class VueSSRClientPlugin {
|
||||
modules: {
|
||||
/* [identifier: string]: Array<index: number> */
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const assetModules = stats.modules.filter((m) => m.assets.length)
|
||||
const fileToIndex = (file) => manifest.all.indexOf(file)
|
||||
const assetModules = stats.modules.filter((m) => m.assets.length);
|
||||
const fileToIndex = (asset) => manifest.all.indexOf(getAssetName(asset));
|
||||
stats.modules.forEach((m) => {
|
||||
// ignore modules duplicated in multiple chunks
|
||||
if (m.chunks.length === 1) {
|
||||
const cid = m.chunks[0]
|
||||
const chunk = stats.chunks.find((c) => c.id === cid)
|
||||
const cid = m.chunks[0];
|
||||
const chunk = stats.chunks.find((c) => c.id === cid);
|
||||
if (!chunk || !chunk.files) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
const id = m.identifier.replace(/\s\w+$/, '') // remove appended hash
|
||||
const files = (manifest.modules[hash(id)] = chunk.files.map(
|
||||
fileToIndex
|
||||
))
|
||||
const id = stripModuleIdHash(m.identifier);
|
||||
const files = (manifest.modules[hash(id)] =
|
||||
chunk.files.map(fileToIndex));
|
||||
// find all asset modules associated with the same chunk
|
||||
assetModules.forEach((m) => {
|
||||
if (m.chunks.some((id) => id === cid)) {
|
||||
files.push.apply(files, m.assets.map(fileToIndex))
|
||||
files.push.apply(files, m.assets.map(fileToIndex));
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const json = JSON.stringify(manifest, null, 2)
|
||||
//@ts-expect-error
|
||||
const json = JSON.stringify(manifest, null, 2);
|
||||
//@ts-expect-error no type on options
|
||||
compilation.assets[this.options.filename] = {
|
||||
source: () => json,
|
||||
size: () => json.length,
|
||||
}
|
||||
cb()
|
||||
})
|
||||
};
|
||||
cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { validate, isJS, onEmit } from './util'
|
||||
import { validate, isJS, getAssetName, onEmit } from './util'
|
||||
|
||||
export default class VueSSRServerPlugin {
|
||||
constructor(options = {}) {
|
||||
@ -14,7 +14,8 @@ export default class VueSSRServerPlugin {
|
||||
apply(compiler) {
|
||||
validate(compiler)
|
||||
|
||||
onEmit(compiler, 'vue-server-plugin', (compilation, cb) => {
|
||||
const stage = 'PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER'
|
||||
onEmit(compiler, 'vue-server-plugin', stage, (compilation, cb) => {
|
||||
const stats = compilation.getStats().toJson()
|
||||
const entryName = Object.keys(stats.entrypoints)[0]
|
||||
const entryInfo = stats.entrypoints[entryName]
|
||||
@ -24,7 +25,9 @@ export default class VueSSRServerPlugin {
|
||||
return cb()
|
||||
}
|
||||
|
||||
const entryAssets = entryInfo.assets.filter(isJS)
|
||||
const entryAssets = entryInfo.assets
|
||||
.map(getAssetName)
|
||||
.filter(isJS)
|
||||
|
||||
if (entryAssets.length > 1) {
|
||||
throw new Error(
|
||||
@ -46,16 +49,14 @@ export default class VueSSRServerPlugin {
|
||||
maps: {},
|
||||
}
|
||||
|
||||
stats.assets.forEach((asset) => {
|
||||
if (isJS(asset.name)) {
|
||||
bundle.files[asset.name] = compilation.assets[asset.name].source()
|
||||
} else if (asset.name.match(/\.js\.map$/)) {
|
||||
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(
|
||||
compilation.assets[asset.name].source()
|
||||
)
|
||||
Object.keys(compilation.assets).forEach(name => {
|
||||
if (isJS(name)) {
|
||||
bundle.files[name] = compilation.assets[name].source()
|
||||
} else if (name.match(/\.js\.map$/)) {
|
||||
bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source())
|
||||
}
|
||||
// do not emit anything else for server
|
||||
delete compilation.assets[asset.name]
|
||||
delete compilation.assets[name]
|
||||
})
|
||||
|
||||
const json = JSON.stringify(bundle, null, 2)
|
||||
|
@ -1,20 +1,28 @@
|
||||
const { red, yellow } = require('chalk')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const prefix = `[vue-server-renderer-webpack-plugin]`
|
||||
const warn = (exports.warn = (msg) => console.error(red(`${prefix} ${msg}\n`)))
|
||||
const tip = (exports.tip = (msg) => console.log(yellow(`${prefix} ${msg}\n`)))
|
||||
const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`))
|
||||
const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`))
|
||||
|
||||
export const validate = (compiler) => {
|
||||
const isWebpack5 = !!(webpack.version && webpack.version[0] > 4)
|
||||
|
||||
export const validate = compiler => {
|
||||
if (compiler.options.target !== 'node') {
|
||||
warn('webpack config `target` should be "node".')
|
||||
}
|
||||
|
||||
if (
|
||||
compiler.options.output &&
|
||||
compiler.options.output.libraryTarget !== 'commonjs2'
|
||||
) {
|
||||
if (compiler.options.output) {
|
||||
if (compiler.options.output.library) {
|
||||
// Webpack >= 5.0.0
|
||||
if (compiler.options.output.library.type !== 'commonjs2') {
|
||||
warn('webpack config `output.library.type` should be "commonjs2".')
|
||||
}
|
||||
} else if (compiler.options.output.libraryTarget !== 'commonjs2') {
|
||||
// Webpack < 5.0.0
|
||||
warn('webpack config `output.libraryTarget` should be "commonjs2".')
|
||||
}
|
||||
}
|
||||
|
||||
if (!compiler.options.externals) {
|
||||
tip(
|
||||
@ -24,8 +32,20 @@ export const validate = (compiler) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const onEmit = (compiler, name, hook) => {
|
||||
if (compiler.hooks) {
|
||||
export const onEmit = (compiler, name, stageName, hook) => {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
compiler.hooks.compilation.tap(name, compilation => {
|
||||
if (compilation.compiler !== compiler) {
|
||||
// Ignore child compilers
|
||||
return
|
||||
}
|
||||
const stage = webpack.Compilation[stageName]
|
||||
compilation.hooks.processAssets.tapAsync({ name, stage }, (assets, cb) => {
|
||||
hook(compilation, cb)
|
||||
})
|
||||
})
|
||||
} else if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook)
|
||||
} else {
|
||||
@ -34,4 +54,20 @@ export const onEmit = (compiler, name, hook) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const stripModuleIdHash = id => {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
return id.replace(/\|\w+$/, '')
|
||||
}
|
||||
// Webpack < 5.0.0
|
||||
return id.replace(/\s\w+$/, '')
|
||||
}
|
||||
|
||||
export const getAssetName = asset => {
|
||||
if (typeof asset === 'string') {
|
||||
return asset
|
||||
}
|
||||
return asset.name
|
||||
}
|
||||
|
||||
export { isJS, isCSS } from '../util'
|
||||
|
@ -34,7 +34,7 @@ export function createWriteFunction(
|
||||
defer(() => {
|
||||
try {
|
||||
next()
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
onError(e)
|
||||
}
|
||||
})
|
||||
|
@ -34,7 +34,7 @@ export function isPrimitive(value: any): boolean {
|
||||
|
||||
/**
|
||||
* Quick object check - this is primarily used to tell
|
||||
* Objects from primitive values when we know the value
|
||||
* objects from primitive values when we know the value
|
||||
* is a JSON-compliant type.
|
||||
*/
|
||||
export function isObject(obj: any): boolean {
|
||||
@ -314,7 +314,7 @@ export function looseEqual(a: any, b: any): boolean {
|
||||
/* istanbul ignore next */
|
||||
return false
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
/* istanbul ignore next */
|
||||
return false
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ describe('SSR: basicRenderer', () => {
|
||||
})
|
||||
|
||||
// #5941
|
||||
it('should work peoperly when accessing $ssrContext in root component', done => {
|
||||
it('should work properly when accessing $ssrContext in root component', done => {
|
||||
let ssrContext
|
||||
renderToString(new Vue({
|
||||
template: `
|
||||
|
@ -694,6 +694,34 @@ describe('SSR: renderToString', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// #11963, #10391
|
||||
it('renders async children passed in slots', done => {
|
||||
const Parent = {
|
||||
template: `<div><slot name="child"/></div>`
|
||||
}
|
||||
const Child = {
|
||||
template: `<p>child</p>`
|
||||
}
|
||||
renderVmWithOptions({
|
||||
template: `
|
||||
<Parent>
|
||||
<template #child>
|
||||
<Child/>
|
||||
</template>
|
||||
</Parent>
|
||||
`,
|
||||
components: {
|
||||
Parent,
|
||||
Child: () => Promise.resolve(Child)
|
||||
}
|
||||
}, result => {
|
||||
expect(result).toContain(
|
||||
`<div data-server-rendered="true"><p>child</p></div>`
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('everything together', done => {
|
||||
renderVmWithOptions({
|
||||
template: `
|
||||
@ -1323,7 +1351,7 @@ describe('SSR: renderToString', () => {
|
||||
</div>
|
||||
`
|
||||
}, result => {
|
||||
expect(result).toContain(`<div class="a\nb"></div>`)
|
||||
expect(result).toContain(`<div class="a b"></div>`)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
@ -7,7 +7,7 @@ describe('Component async', () => {
|
||||
const oldClearTimeout = window.clearTimeout;
|
||||
|
||||
// will contain pending timeouts set during the test iteration
|
||||
// will contain the id of the timeout as the key, and the the millisecond timeout as the value
|
||||
// will contain the id of the timeout as the key, and the millisecond timeout as the value
|
||||
// this helps to identify the timeout that is still pending
|
||||
let timeoutsPending = {};
|
||||
|
||||
|
@ -572,6 +572,73 @@ describe('Component keep-alive', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('max=1', done => {
|
||||
const spyA = jasmine.createSpy()
|
||||
const spyB = jasmine.createSpy()
|
||||
const spyC = jasmine.createSpy()
|
||||
const spyAD = jasmine.createSpy()
|
||||
const spyBD = jasmine.createSpy()
|
||||
const spyCD = jasmine.createSpy()
|
||||
|
||||
function assertCount (calls) {
|
||||
expect([
|
||||
spyA.calls.count(),
|
||||
spyAD.calls.count(),
|
||||
spyB.calls.count(),
|
||||
spyBD.calls.count(),
|
||||
spyC.calls.count(),
|
||||
spyCD.calls.count()
|
||||
]).toEqual(calls)
|
||||
}
|
||||
|
||||
const vm = new Vue({
|
||||
template: `
|
||||
<keep-alive max="1">
|
||||
<component :is="n"></component>
|
||||
</keep-alive>
|
||||
`,
|
||||
data: {
|
||||
n: 'aa'
|
||||
},
|
||||
components: {
|
||||
aa: {
|
||||
template: '<div>a</div>',
|
||||
created: spyA,
|
||||
destroyed: spyAD
|
||||
},
|
||||
bb: {
|
||||
template: '<div>bbb</div>',
|
||||
created: spyB,
|
||||
destroyed: spyBD
|
||||
},
|
||||
cc: {
|
||||
template: '<div>ccc</div>',
|
||||
created: spyC,
|
||||
destroyed: spyCD
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
assertCount([1, 0, 0, 0, 0, 0])
|
||||
vm.n = 'bb'
|
||||
waitForUpdate(() => {
|
||||
// should prune A because max cache reached
|
||||
assertCount([1, 1, 1, 0, 0, 0])
|
||||
vm.n = 'cc'
|
||||
}).then(() => {
|
||||
// should prune B because max cache reached
|
||||
assertCount([1, 1, 1, 1, 1, 0])
|
||||
vm.n = 'bb'
|
||||
}).then(() => {
|
||||
// B is recreated
|
||||
assertCount([1, 1, 2, 1, 1, 1])
|
||||
vm.n = 'aa'
|
||||
}).then(() => {
|
||||
// B is destroyed and A recreated
|
||||
assertCount([2, 1, 2, 2, 1, 1])
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should warn unknown component inside', () => {
|
||||
new Vue({
|
||||
template: `<keep-alive><foo/></keep-alive>`
|
||||
@ -1182,5 +1249,37 @@ describe('Component keep-alive', () => {
|
||||
}).then(done)
|
||||
}
|
||||
})
|
||||
|
||||
// #10083
|
||||
it('should not attach event handler repeatedly', done => {
|
||||
const vm = new Vue({
|
||||
template: `
|
||||
<keep-alive>
|
||||
<btn v-if="showBtn" @click.native="add" />
|
||||
</keep-alive>
|
||||
`,
|
||||
data: { showBtn: true, n: 0 },
|
||||
methods: {
|
||||
add () {
|
||||
this.n++
|
||||
}
|
||||
},
|
||||
components: {
|
||||
btn: { template: '<button>add 1</button>' }
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
const btn = vm.$el
|
||||
expect(vm.n).toBe(0)
|
||||
btn.click()
|
||||
expect(vm.n).toBe(1)
|
||||
vm.showBtn = false
|
||||
waitForUpdate(() => {
|
||||
vm.showBtn = true
|
||||
}).then(() => {
|
||||
btn.click()
|
||||
expect(vm.n).toBe(2)
|
||||
}).then(done)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -1325,4 +1325,28 @@ describe('Component scoped slot', () => {
|
||||
expect(vm.$el.textContent).toMatch(`1`)
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// #11652
|
||||
it('should update when switching between two components with slot and without slot', done => {
|
||||
const Child = {
|
||||
template: `<div><slot/></div>`
|
||||
}
|
||||
|
||||
const parent = new Vue({
|
||||
template: `<div>
|
||||
<child v-if="flag"><template #default>foo</template></child>
|
||||
<child v-else></child>
|
||||
</div>`,
|
||||
data: {
|
||||
flag: true
|
||||
},
|
||||
components: { Child }
|
||||
}).$mount()
|
||||
|
||||
expect(parent.$el.textContent).toMatch(`foo`)
|
||||
parent.flag=false
|
||||
waitForUpdate(()=>{
|
||||
expect(parent.$el.textContent).toMatch(``)
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
@ -109,6 +109,47 @@ describe('Component slot', () => {
|
||||
expect(child.$el.children[1].textContent).toBe('slot b')
|
||||
})
|
||||
|
||||
it('it should work with previous versions of the templates', () => {
|
||||
const Test = {
|
||||
render() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || vm._h;
|
||||
return _c('div', [_vm._t("default", [_c('p', [_vm._v("slot default")])])], 2)
|
||||
}
|
||||
}
|
||||
let vm = new Vue({
|
||||
template: `<test/>`,
|
||||
components: { Test }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('slot default')
|
||||
vm = new Vue({
|
||||
template: `<test>custom content</test>`,
|
||||
components: { Test }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('custom content')
|
||||
})
|
||||
|
||||
it('fallback content should not be evaluated when the parent is providing it', () => {
|
||||
const test = jasmine.createSpy('test')
|
||||
const vm = new Vue({
|
||||
template: '<test>slot default</test>',
|
||||
components: {
|
||||
test: {
|
||||
template: '<div><slot>{{test()}}</slot></div>',
|
||||
methods: {
|
||||
test () {
|
||||
test()
|
||||
return 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('slot default')
|
||||
expect(test).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('selector matching multiple elements', () => {
|
||||
mount({
|
||||
childTemplate: '<div><slot name="t"></slot></div>',
|
||||
@ -945,4 +986,18 @@ describe('Component slot', () => {
|
||||
expect(vm.$el.firstChild.innerHTML).toBe('<span><b>2</b></span>')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// #12102
|
||||
it('v-if inside scoped slot', () => {
|
||||
const vm = new Vue({
|
||||
template: `<test><template #custom><span v-if="false">a</span><span>b</span></template></test>`,
|
||||
components: {
|
||||
test: {
|
||||
template: `<div><slot name="custom"/></div>`
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.innerHTML).toBe(`<!----><span>b</span>`)
|
||||
})
|
||||
})
|
||||
|
@ -152,6 +152,39 @@ describe('Directive v-bind:class', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// css static classes should only contain a single space in between,
|
||||
// as all the text inside of classes is shipped as a JS string
|
||||
// and this could lead to useless spacing in static classes
|
||||
it('condenses whitespace in staticClass', done => {
|
||||
const vm = new Vue({
|
||||
template: '<div class=" test1\ntest2\ttest3 test4 test5 \n \n \ntest6\t"></div>',
|
||||
}).$mount()
|
||||
expect(vm.$el.className).toBe('test1 test2 test3 test4 test5 test6')
|
||||
done()
|
||||
})
|
||||
|
||||
it('condenses whitespace in staticClass merge in a component', done => {
|
||||
const vm = new Vue({
|
||||
template: `
|
||||
<component1 class="\n\t staticClass \t\n" :class="componentClass1">
|
||||
</component1>
|
||||
`,
|
||||
data: {
|
||||
componentClass1: 'componentClass1',
|
||||
},
|
||||
components: {
|
||||
component1: {
|
||||
template: '<div class="\n\t test \t\n"></div>'
|
||||
},
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.className).toBe('test staticClass componentClass1')
|
||||
vm.componentClass1 = 'c1'
|
||||
waitForUpdate(() => {
|
||||
expect(vm.$el.className).toBe('test staticClass c1')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// a vdom patch edge case where the user has several un-keyed elements of the
|
||||
// same tag next to each other, and toggling them.
|
||||
it('properly remove staticClass for toggling un-keyed children', done => {
|
||||
|
@ -31,7 +31,7 @@ describe('Directive v-on', () => {
|
||||
expect(event.type).toBe('click')
|
||||
})
|
||||
|
||||
it('should bind event to a inline statement', () => {
|
||||
it('should bind event to an inline statement', () => {
|
||||
vm = new Vue({
|
||||
el,
|
||||
template: '<div v-on:click="foo(1,2,3,$event)"></div>',
|
||||
@ -218,7 +218,7 @@ describe('Directive v-on', () => {
|
||||
})
|
||||
|
||||
// ctrl, shift, alt, meta
|
||||
it('should support system modifers', () => {
|
||||
it('should support system modifiers', () => {
|
||||
vm = new Vue({
|
||||
el,
|
||||
template: `
|
||||
@ -976,6 +976,17 @@ describe('Directive v-on', () => {
|
||||
expect(value).toBe(1)
|
||||
})
|
||||
|
||||
it('should not execute callback if modifiers are present', () => {
|
||||
vm = new Vue({
|
||||
el,
|
||||
template: '<input @keyup.?="foo">',
|
||||
methods: { foo: spy }
|
||||
})
|
||||
// simulating autocomplete event (Event object with type keyup but without keyCode)
|
||||
triggerEvent(vm.$el, 'keyup')
|
||||
expect(spy.calls.count()).toBe(0)
|
||||
})
|
||||
|
||||
describe('dynamic arguments', () => {
|
||||
it('basic', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
@ -127,26 +127,26 @@ describe('Error handling', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should recover from errors in user watcher callback', done => {
|
||||
const vm = createTestInstance(components.userWatcherCallback)
|
||||
vm.n++
|
||||
waitForUpdate(() => {
|
||||
expect(`Error in callback for watcher "n"`).toHaveBeenWarned()
|
||||
expect(`Error: userWatcherCallback`).toHaveBeenWarned()
|
||||
}).thenWaitFor(next => {
|
||||
assertBothInstancesActive(vm).end(next)
|
||||
;[
|
||||
['userWatcherCallback', 'watcher'],
|
||||
['userImmediateWatcherCallback', 'immediate watcher']
|
||||
].forEach(([type, description]) => {
|
||||
it(`should recover from errors in user ${description} callback`, done => {
|
||||
const vm = createTestInstance(components[type])
|
||||
assertBothInstancesActive(vm).then(() => {
|
||||
expect(`Error in callback for ${description} "n"`).toHaveBeenWarned()
|
||||
expect(`Error: ${type} error`).toHaveBeenWarned()
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should recover from errors in user immediate watcher callback', done => {
|
||||
const vm = createTestInstance(components.userImmediateWatcherCallback)
|
||||
waitForUpdate(() => {
|
||||
expect(`Error in callback for immediate watcher "n"`).toHaveBeenWarned()
|
||||
expect(`Error: userImmediateWatcherCallback error`).toHaveBeenWarned()
|
||||
}).thenWaitFor(next => {
|
||||
assertBothInstancesActive(vm).end(next)
|
||||
it(`should recover from promise errors in user ${description} callback`, done => {
|
||||
const vm = createTestInstance(components[`${type}Async`])
|
||||
assertBothInstancesActive(vm).then(() => {
|
||||
expect(`Error in callback for ${description} "n" (Promise/async)`).toHaveBeenWarned()
|
||||
expect(`Error: ${type} error`).toHaveBeenWarned()
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
||||
it('config.errorHandler should capture render errors', done => {
|
||||
const spy = Vue.config.errorHandler = jasmine.createSpy('errorHandler')
|
||||
@ -359,6 +359,33 @@ function createErrorTestComponents () {
|
||||
}
|
||||
}
|
||||
|
||||
components.userWatcherCallbackAsync = {
|
||||
props: ['n'],
|
||||
watch: {
|
||||
n () {
|
||||
return Promise.reject(new Error('userWatcherCallback error'))
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
return h('div', this.n)
|
||||
}
|
||||
}
|
||||
|
||||
components.userImmediateWatcherCallbackAsync = {
|
||||
props: ['n'],
|
||||
watch: {
|
||||
n: {
|
||||
immediate: true,
|
||||
handler () {
|
||||
return Promise.reject(new Error('userImmediateWatcherCallback error'))
|
||||
}
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
return h('div', this.n)
|
||||
}
|
||||
}
|
||||
|
||||
// event errors
|
||||
components.event = {
|
||||
beforeCreate () {
|
||||
|
@ -14,7 +14,7 @@ describe('Global API: set/delete', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should update a observing object', done => {
|
||||
it('should update an observing object', done => {
|
||||
const vm = new Vue({
|
||||
template: '<div>{{foo.x}}</div>',
|
||||
data: { foo: { x: 1 }}
|
||||
@ -26,7 +26,7 @@ describe('Global API: set/delete', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should update a observing array', done => {
|
||||
it('should update an observing array', done => {
|
||||
const vm = new Vue({
|
||||
template: '<div><div v-for="v,k in list">{{k}}-{{v}}</div></div>',
|
||||
data: { list: ['a', 'b', 'c'] }
|
||||
|
@ -206,6 +206,18 @@ describe('Options computed', () => {
|
||||
expect(`computed property "a" is already defined as a prop`).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('warn conflict with methods', () => {
|
||||
new Vue({
|
||||
computed: {
|
||||
a: () => 2
|
||||
},
|
||||
methods: {
|
||||
a: () => {}
|
||||
}
|
||||
})
|
||||
expect(`computed property "a" is already defined as a method`).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('rethrow computed error', () => {
|
||||
const vm = new Vue({
|
||||
computed: {
|
||||
|
@ -247,4 +247,152 @@ describe('Options errorCaptured', () => {
|
||||
expect(store.errors[0]).toEqual(new Error('render error'))
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should capture error from watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo () {
|
||||
err = new Error('userWatcherCallback error')
|
||||
throw err
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
child.foo = 'bar'
|
||||
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo"')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo"')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should capture promise error from watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo () {
|
||||
err = new Error('userWatcherCallback error')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
child.foo = 'bar'
|
||||
|
||||
child.$nextTick(() => {
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo" (Promise/async)')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo" (Promise/async)')
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
||||
it('should capture error from immediate watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: 'foo'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo: {
|
||||
immediate: true,
|
||||
handler () {
|
||||
err = new Error('userImmediateWatcherCallback error')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo"')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo"')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should capture promise error from immediate watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: 'foo'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo: {
|
||||
immediate: true,
|
||||
handler () {
|
||||
err = new Error('userImmediateWatcherCallback error')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo" (Promise/async)')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo" (Promise/async)')
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
@ -32,7 +32,7 @@ const webpackConfig = {
|
||||
}
|
||||
})
|
||||
],
|
||||
devtool: '#inline-source-map'
|
||||
devtool: 'inline-source-map'
|
||||
}
|
||||
|
||||
// shared config for all unit tests
|
||||
|
@ -196,7 +196,7 @@ describe('codegen', () => {
|
||||
it('generate slot fallback content', () => {
|
||||
assertCodegen(
|
||||
'<div><slot><div>hi</div></slot></div>',
|
||||
`with(this){return _c('div',[_t("default",[_c('div',[_v("hi")])])],2)}`
|
||||
`with(this){return _c('div',[_t("default",function(){return [_c('div',[_v("hi")])]})],2)}`
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Vue from 'vue'
|
||||
import { SSR_ATTR } from 'shared/constants'
|
||||
|
||||
describe('vdom patch: edge cases', () => {
|
||||
// exposed by #3406
|
||||
@ -432,4 +433,22 @@ describe('vdom patch: edge cases', () => {
|
||||
expect(vm.$el.textContent).not.toMatch('Infinity')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should not throw when hydrated pending async component is patched by v-if="false"', done => {
|
||||
const PendingAsyncComponent = () => new Promise(() => {})
|
||||
const ssrAsyncComponent = document.createElement('div')
|
||||
ssrAsyncComponent.setAttribute(SSR_ATTR, 'true')
|
||||
const vm = new Vue({
|
||||
data: {
|
||||
visible: true
|
||||
},
|
||||
components: {
|
||||
PendingAsyncComponent
|
||||
},
|
||||
template: '<pending-async-component v-if="visible"></pending-async-component>'
|
||||
}).$mount(ssrAsyncComponent)
|
||||
|
||||
vm.visible = false
|
||||
vm.$nextTick(done)
|
||||
})
|
||||
})
|
||||
|
15
types/options.d.ts
vendored
15
types/options.d.ts
vendored
@ -12,9 +12,10 @@ export type Component<Data=DefaultData<never>, Methods=DefaultMethods<never>, Co
|
||||
| FunctionalComponentOptions<Props>
|
||||
| ComponentOptions<never, Data, Methods, Computed, Props>
|
||||
|
||||
interface EsModuleComponent {
|
||||
default: Component
|
||||
}
|
||||
type EsModule<T> = T | { default: T }
|
||||
|
||||
type ImportedComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
|
||||
= EsModule<Component<Data, Methods, Computed, Props>>
|
||||
|
||||
export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
|
||||
= AsyncComponentPromise<Data, Methods, Computed, Props>
|
||||
@ -23,12 +24,12 @@ export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never
|
||||
export type AsyncComponentPromise<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = (
|
||||
resolve: (component: Component<Data, Methods, Computed, Props>) => void,
|
||||
reject: (reason?: any) => void
|
||||
) => Promise<Component | EsModuleComponent> | void;
|
||||
) => Promise<ImportedComponent<Data, Methods, Computed, Props>> | void;
|
||||
|
||||
export type AsyncComponentFactory<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = () => {
|
||||
component: AsyncComponentPromise<Data, Methods, Computed, Props>;
|
||||
loading?: Component | EsModuleComponent;
|
||||
error?: Component | EsModuleComponent;
|
||||
component: Promise<ImportedComponent<Data, Methods, Computed, Props>>;
|
||||
loading?: ImportedComponent;
|
||||
error?: ImportedComponent;
|
||||
delay?: number;
|
||||
timeout?: number;
|
||||
}
|
||||
|
44
types/test/async-component-test.ts
Normal file
44
types/test/async-component-test.ts
Normal 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
2
types/vue.d.ts
vendored
@ -26,7 +26,7 @@ export interface Vue {
|
||||
readonly $parent: Vue;
|
||||
readonly $root: Vue;
|
||||
readonly $children: Vue[];
|
||||
readonly $refs: { [key: string]: Vue | Element | Vue[] | Element[] };
|
||||
readonly $refs: { [key: string]: Vue | Element | (Vue | Element)[] | undefined };
|
||||
readonly $slots: { [key: string]: VNode[] | undefined };
|
||||
readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined };
|
||||
readonly $isServer: boolean;
|
||||
|
2
typescript/component.d.ts
vendored
2
typescript/component.d.ts
vendored
@ -110,7 +110,7 @@ declare class Component {
|
||||
_render: () => VNode;
|
||||
|
||||
__patch__: (
|
||||
a: Element | VNode | void,
|
||||
a: Element | VNode | void | null,
|
||||
b: VNode | null,
|
||||
hydrating?: boolean,
|
||||
removeOnly?: boolean,
|
||||
|
Loading…
Reference in New Issue
Block a user