Compare commits

..

2 Commits
v4.6.3 ... next

Author SHA1 Message Date
chenjiahan
b45b0b7608 chore: update branches in GitHub actions 2022-09-10 21:57:09 +08:00
chenjiahan
c309ca2aaf docs: switch dev branch to v4 2022-09-10 21:53:49 +08:00
1067 changed files with 7638 additions and 62894 deletions

View File

@ -0,0 +1,5 @@
注意gitee 中为 vant 的镜像仓库,不进行 issue 处理。
请移步 GitHub issues 进行反馈:
https://github.com/vant-ui/vant/issues

View File

@ -1,8 +1 @@
blank_issues_enabled: true blank_issues_enabled: true
contact_links:
- name: Ask a question
url: https://github.com/youzan/vant/discussions
about: Ask a question about Vant
- name: 提问
url: https://github.com/youzan/vant/discussions
about: 询问 Vant 的用法问题

View File

@ -1,6 +1,6 @@
### Before submitting a pull request, please make sure the following is done: ### Before submitting a pull request, please make sure the following is done:
1. Read the [contributing guide](https://github.com/vant-ui/vant/blob/main/.github/CONTRIBUTING.md). 1. Read the [contributing guide](https://github.com/vant-ui/vant/blob/dev/.github/CONTRIBUTING.md).
2. If you've added code that should be tested, add tests. 2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation. 3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes (`npm test`). 4. Ensure the test suite passes (`npm test`).

View File

@ -13,10 +13,10 @@ name: "CodeQL"
on: on:
push: push:
branches: [ main ] branches: [ dev ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ main ] branches: [ dev ]
schedule: schedule:
- cron: '36 21 * * 2' - cron: '36 21 * * 2'

View File

@ -2,7 +2,7 @@ name: Deploy V4 Site
on: on:
push: push:
branches: [main] branches: [dev]
paths: paths:
- 'packages/vant/docs/**' - 'packages/vant/docs/**'
@ -15,14 +15,14 @@ jobs:
- name: Checkout 🛎️ - name: Checkout 🛎️
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
ref: 'main' ref: 'next'
- name: Install pnpm - name: Install pnpm
run: corepack enable run: npm i pnpm@7 -g
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: '18' node-version: '16'
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
@ -31,49 +31,10 @@ jobs:
- name: Build Site - name: Build Site
run: npm run build:site run: npm run build:site
- name: Deploy for Gitee 🚀 - name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4.4.0 uses: JamesIves/github-pages-deploy-action@4.1.1
with: with:
branch: gh-pages branch: gh-pages
folder: packages/vant/site-dist folder: packages/vant/site-dist
clean: true target-folder: v4
clean-exclude: | clean: false
1.x/*
1.x/**/*
next/*
next/**/*
v1/*
v1/**/*
v2/*
v2/**/*
v3/*
v3/**/*
v4/*
v4/**/*
vant-use/*
vant-use/**/*
- name: Deploy for GitHub 🚀
uses: JamesIves/github-pages-deploy-action@v4.4.1
with:
branch: main
folder: packages/vant/site-dist
token: ${{ secrets.VANT_UI_TOKEN }}
repository-name: vant-ui/vant-ui.github.io
target-folder: vant
clean: true
clean-exclude: |
1.x/*
1.x/**/*
next/*
next/**/*
v1/*
v1/**/*
v2/*
v2/**/*
v3/*
v3/**/*
v4/*
v4/**/*
vant-use/*
vant-use/**/*

View File

@ -1,25 +0,0 @@
name: Issue Close Require
on:
schedule:
- cron: '0 0 * * *'
permissions:
contents: read
jobs:
issue-close-require:
permissions:
issues: write
runs-on: ubuntu-latest
steps:
- name: need reproduce
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: 'need reproduce'
inactive-day: 3
body: |
Since the issue was labeled with `need reproduce`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.
由于该 issue 被标记为需要复现,却 3 天未收到回应。现关闭 issue若有任何问题可评论回复。

View File

@ -1,69 +0,0 @@
name: Issue Labeled
on:
issues:
types: [labeled]
permissions:
contents: read
jobs:
reply-labeled:
permissions:
issues: write
runs-on: ubuntu-latest
steps:
- name: help wanted
if: github.event.label.name == '👏 PR welcome' || github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to [send us a Pull Request](https://help.github.com/en/articles/creating-a-pull-request) for it. Please send your Pull Request to `main` branch, fill the [Pull Request Template](https://github.com/vant-ui/vant/blob/main/.github/PULL_REQUEST_TEMPLATE.md) here, provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution!
你好 @${{ github.event.issue.user.login }},我们完全同意你的提议/反馈,欢迎直接在此仓库 [创建一个 Pull Request](https://help.github.com/en/articles/creating-a-pull-request) 来解决这个问题。请将 Pull Request 发到 `main` 分支,务必填写 Pull Request 内的[预设模板](https://github.com/vant-ui/vant/blob/main/.github/PULL_REQUEST_TEMPLATE.md),提供改动所需相应的 changelog、TypeScript 定义、测试用例、文档等,并确保 CI 通过,我们会尽快进行 Review提前感谢和期待您的贡献。
- name: need reproduce
if: github.event.label.name == 'need reproduce'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. Please provide an online reproduction demo by clicking this [link](https://codesandbox.io/s/vant-3-issue-template-8fuq5o) or a minimal GitHub repository. Issues marked with `need reproduce` will be closed if they have no activity within 3 days.
你好 @${{ github.event.issue.user.login }}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。可以通过点击 [此处](https://codesandbox.io/s/vant-3-issue-template-8fuq5o) 创建或者提供一个最小化的 GitHub 仓库。3 天内未跟进此 issue 将会被自动关闭。
- name: question
if: github.event.label.name == 'question'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment, close-issue'
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}, we use GitHub issues to trace bugs or discuss plans of Vant. So, please don't ask usage questions here. You can try to open a new discussion in [vant discussions](https://github.com/vant-ui/vant/discussions), select `Q&A` to ask questions.
你好 @${{ github.event.issue.user.login }}Vant Issue 板块是用于 bug 反馈与需求讨论的地方。请勿在这里询问如何使用等相关问题,你可以试着在 [vant discussions](https://github.com/vant-ui/vant/discussions) 新开一个 discussion选择 `Q&A` 类别进行提问。
- name: 2.x
if: github.event.label.name == '2.x'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment, close-issue'
issue-number: ${{ github.event.issue.number }}
body: |
Hi @${{ github.event.issue.user.login }}. Current version (2.x) is off the maintenance period. We will only fix critical bugs. This issue will be auto closed.
你好 @${{ github.event.issue.user.login }}当前版本2.x已经过了维护期。我们仅会修复重要 bug。当前 issue 会被自动关闭。
- name: invalid
if: github.event.label.name == 'invalid'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment, close-issue'
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}, your issue has been closed because it does not conform to our issue requirements.
你好 @${{ github.event.issue.user.login }},为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为不符合要求而被自动关闭。

View File

@ -2,8 +2,7 @@ name: Sync to Gitee
on: on:
push: push:
tags: branches: [dev, 2.x, 3.x, gh-pages]
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
workflow_dispatch: workflow_dispatch:

View File

@ -7,7 +7,7 @@ on:
pull_request: pull_request:
branches: branches:
- main - dev
workflow_dispatch: workflow_dispatch:
@ -18,11 +18,11 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install pnpm - name: Install pnpm
run: corepack enable run: npm i pnpm@7 -g
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: '18' node-version: '16'
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
@ -37,11 +37,11 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install pnpm - name: Install pnpm
run: corepack enable run: npm i pnpm@7 -g
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: '18' node-version: '16'
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
@ -61,11 +61,11 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install pnpm - name: Install pnpm
run: corepack enable run: npm i pnpm@7 -g
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: '18' node-version: '16'
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies

2
.npmrc
View File

@ -1,5 +1,3 @@
registry=https://registry.npmmirror.com/ registry=https://registry.npmmirror.com/
strict-peer-dependencies=false strict-peer-dependencies=false
auto-install-peers=false
resolution-mode=highest

1
.nvmrc
View File

@ -1 +0,0 @@
lts/Hydrogen

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"singleQuote": true,
"proseWrap": "never"
}

View File

@ -4,13 +4,14 @@
<h1 align="center">Vant</h1> <h1 align="center">Vant</h1>
<p align="center">A lightweight, customizable Vue UI library for mobile web apps.</p> <p align="center">Lightweight Mobile UI Components built on Vue</p>
<p align="center"> <p align="center">
<img src="https://img.shields.io/npm/v/vant?style=flat-square" alt="npm version" /> <img src="https://img.shields.io/npm/v/vant?style=flat-square" alt="npm version" />
<img src="https://img.shields.io/github/workflow/status/vant-ui/vant/CI/dev?style=flat-square" alt="CI Status" />
<img src="https://img.shields.io/codecov/c/github/vant-ui/vant/dev.svg?style=flat-square&color=#4fc08d" alt="Coverage Status" /> <img src="https://img.shields.io/codecov/c/github/vant-ui/vant/dev.svg?style=flat-square&color=#4fc08d" alt="Coverage Status" />
<img src="https://img.shields.io/npm/dm/vant.svg?style=flat-square&color=#4fc08d" alt="downloads" /> <img src="https://img.shields.io/npm/dm/vant.svg?style=flat-square&color=#4fc08d" alt="downloads" />
<img src="https://img.badgesize.io/https://unpkg.com/vant/lib/vant.min.js?compression=gzip&style=flat-square&label=gzip%20size&color=#4fc08d" alt="Gzip Size" /> <img src="https://img.badgesize.io/https://unpkg.com/vant@3/lib/vant.min.js?compression=gzip&style=flat-square&label=gzip%20size&color=#4fc08d" alt="Gzip Size" />
</p> </p>
<p align="center"> <p align="center">
@ -26,20 +27,19 @@
## Features ## Features
- 🚀 1KB Component average size (min+gzip) - 🚀 1KB Component average size (min+gzip)
- 🚀 80+ High quality components - 🚀 70+ High quality components
- 🚀 Zero third-party dependencies - 🚀 Zero third-party dependencies
- 💪 90%+ Unit test coverage - 💪 90%+ Unit test coverage
- 💪 Written in TypeScript - 💪 Written in TypeScript
- 📖 Extensive documentation and demos - 📖 Extensive documentation and demos
- 📖 Provide Sketch and Axure design resources - 📖 Provide Sketch and Axure design resources
- 🍭 Support Vue 2 & Vue 3 - 🍭 Support Vue 2 & Vue 3
- 🍭 Support Nuxt 2 & Nuxt 3, provide [Vant Module](https://github.com/vant-ui/vant-nuxt) for Nuxt
- 🍭 Support Tree Shaking - 🍭 Support Tree Shaking
- 🍭 Support Custom Theme - 🍭 Support Custom Theme
- 🍭 Support Accessibility (still improving) - 🍭 Support Accessibility (still improving)
- 🍭 Support Dark Mode - 🍭 Support Dark Mode (Requires upgrade to [Vant 4](https://vant-contrib.gitee.io/vant/v4/#/en-US/config-provider))
- 🍭 Support SSR - 🍭 Support SSR
- 🌍 Support i18n, built-in 30+ languages - 🌍 Support i18n, built-in 20+ languages
## Install ## Install
@ -92,16 +92,16 @@ Vant 3/4 supports modern browsers and Chrome >= 51、iOS >= 10.0 (same as Vue 3)
| --- | --- | | --- | --- |
| [vant-weapp](https://github.com/vant-ui/vant-weapp) | WeChat MiniProgram UI | | [vant-weapp](https://github.com/vant-ui/vant-weapp) | WeChat MiniProgram UI |
| [vant-demo](https://github.com/vant-ui/vant-demo) | Collection of Vant demos | | [vant-demo](https://github.com/vant-ui/vant-demo) | Collection of Vant demos |
| [vant-cli](https://github.com/vant-ui/vant/tree/main/packages/vant-cli) | Scaffold for UI library | | [vant-cli](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli) | Scaffold for UI library |
| [vant-icons](https://github.com/vant-ui/vant/tree/main/packages/vant-icons) | Vant icons | | [vant-icons](https://github.com/vant-ui/vant/tree/dev/packages/vant-icons) | Vant icons |
| [vant-touch-emulator](https://github.com/vant-ui/vant/tree/main/packages/vant-touch-emulator) | Using vant in desktop browsers | | [vant-touch-emulator](https://github.com/vant-ui/vant/tree/dev/packages/vant-touch-emulator) | Using vant in desktop browsers |
| [vant-nuxt](https://github.com/vant-ui/vant-nuxt) | Vant module for Nuxt |
## Community Ecosystem ## Community Ecosystem
| Project | Description | | Project | Description |
| --- | --- | | --- | --- |
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | React mobile UI Components based on Vant | | [3lang3/react-vant](https://github.com/3lang3/react-vant) | React mobile UI Components based on Vant |
| [rc-ui-lib](https://github.com/rancui/rc-ui-lib) | React mobile UI Components based on Vant |
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Alipay MiniProgram UI | | [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Alipay MiniProgram UI |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro | | [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro |
| [vant-theme](https://github.com/Aisen60/vant-theme) | Online theme preview built on Vant UI | | [vant-theme](https://github.com/Aisen60/vant-theme) | Online theme preview built on Vant UI |
@ -112,7 +112,7 @@ Vant 3/4 supports modern browsers and Chrome >= 51、iOS >= 10.0 (same as Vue 3)
- [Documentation](https://vant-ui.github.io/vant) - [Documentation](https://vant-ui.github.io/vant)
- [Changelog](https://vant-ui.github.io/vant#/en-US/changelog) - [Changelog](https://vant-ui.github.io/vant#/en-US/changelog)
- [Discussions](https://github.com/vant-ui/vant/discussions) - [Gitter](https://gitter.im/vant-contrib/discuss?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
## Preview ## Preview
@ -124,13 +124,9 @@ You can scan the following QR code to access the demo
Core contributors of Vant and Vant Weapp: Core contributors of Vant and Vant Weapp:
| [![chenjiahan](https://avatars.githubusercontent.com/u/7237365?s=80&v=4)](https://github.com/chenjiahan/) | [![cookfront](https://avatars.githubusercontent.com/u/4829465?s=80&v=4)](https://github.com/cookfront/) | [![w91](https://avatars.githubusercontent.com/u/2599455?s=80&v=4)](https://github.com/w91/) | [![pangxie1991](https://avatars.githubusercontent.com/u/5961240?s=80&v=4)](https://github.com/pangxie1991/) | [![rex-zsd](https://avatars.githubusercontent.com/u/8767877?s=80&v=4)](https://github.com/rex-zsd/) | [![nemo-shen](https://avatars.githubusercontent.com/u/13480805?s=80&v=4)](https://github.com/nemo-shen/) | | [![chenjiahan](https://avatars.githubusercontent.com/u/7237365?s=80&v=4)](https://github.com/chenjiahan/) | [![cookfront](https://avatars.githubusercontent.com/u/4829465?s=80&v=4)](https://github.com/cookfront/) | [![w91](https://avatars.githubusercontent.com/u/2599455?s=80&v=4)](https://github.com/w91/) | [![pangxie1991](https://avatars.githubusercontent.com/u/5961240?s=80&v=4)](https://github.com/pangxie1991/) | [![rex-zsd](https://avatars.githubusercontent.com/u/8767877?s=80&v=4)](https://github.com/rex-zsd/) | [![nemo-shen](https://avatars.githubusercontent.com/u/13480805?s=80&v=4)](https://github.com/nemo-shen/) | [![Lindysen](https://avatars.githubusercontent.com/u/33708359?s=80&v=4)](https://github.com/Lindysen/) | [![nemo-shen](https://avatars.githubusercontent.com/u/16181940?s=80&v=4)](https://github.com/JakeLaoyu/) |
| :-: | :-: | :-: | :-: | :-: | :-: | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| [chenjiahan](https://github.com/chenjiahan/) | [cookfront](https://github.com/cookfront/) | [wangnaiyi](https://github.com/w91/) | [pangxie](https://github.com/pangxie1991/) | [rex-zsd](https://github.com/rex-zsd/) | [nemo-shen](https://github.com/nemo-shen/) | | [chenjiahan](https://github.com/chenjiahan/) | [cookfront](https://github.com/cookfront/) | [wangnaiyi](https://github.com/w91/) | [pangxie](https://github.com/pangxie1991/) | [rex-zsd](https://github.com/rex-zsd/) | [nemo-shen](https://github.com/nemo-shen/) | [Lindysen](https://github.com/Lindysen/) | [JakeLaoyu](https://github.com/JakeLaoyu/) |
| [![Lindysen](https://avatars.githubusercontent.com/u/33708359?s=80&v=4)](https://github.com/Lindysen/) | [![JakeLaoyu](https://avatars.githubusercontent.com/u/16181940?s=80&v=4)](https://github.com/JakeLaoyu/) | [![landluck](https://avatars.githubusercontent.com/u/27060081?s=80&v=4)](https://github.com/landluck/) | [![wjw-gavin](https://avatars.githubusercontent.com/u/19986739?s=80&v=4)](https://github.com/wjw-gavin/) | [![inottn](https://avatars.githubusercontent.com/u/18509404?s=80&v=4)](https://github.com/inottn/) | [![zhousg](https://avatars.githubusercontent.com/u/15833290?s=80&v=4)](https://github.com/zhousg/) |
| :-: | :-: | :-: | :-: | :-: | :-: |
| [Lindysen](https://github.com/Lindysen/) | [JakeLaoyu](https://github.com/JakeLaoyu/) | [landluck](https://github.com/landluck/) | [wjw-gavin](https://github.com/wjw-gavin/) | [inottn](https://github.com/inottn/) | [zhousg](https://github.com/zhousg/) |
## All Contributors ## All Contributors
@ -144,10 +140,6 @@ Thanks to the following friends for their contributions to Vant:
Please make sure to read the [Contributing Guide](./.github/CONTRIBUTING.md) before making a pull request. Please make sure to read the [Contributing Guide](./.github/CONTRIBUTING.md) before making a pull request.
## Start On Web IDE
[https://github.dev/youzan/vant](https://github.dev/youzan/vant)
## LICENSE ## LICENSE
Vant is [MIT](https://github.com/youzan/vant/blob/main/LICENSE) licensed. [MIT](https://en.wikipedia.org/wiki/MIT_License)

View File

@ -4,13 +4,14 @@
<h1 align="center">Vant</h1> <h1 align="center">Vant</h1>
<p align="center">轻量、可定制的移动端 Vue 组件库</p> <p align="center">轻量、可的移动端 Vue 组件库</p>
<p align="center"> <p align="center">
<img src="https://img.shields.io/npm/v/vant?style=flat-square" alt="npm version" /> <img src="https://img.shields.io/npm/v/vant?style=flat-square" alt="npm version" />
<img src="https://img.shields.io/github/workflow/status/vant-ui/vant/CI/dev?style=flat-square" alt="CI Status" />
<img src="https://img.shields.io/codecov/c/github/vant-ui/vant/dev.svg?style=flat-square&color=#4fc08d" alt="Coverage Status" /> <img src="https://img.shields.io/codecov/c/github/vant-ui/vant/dev.svg?style=flat-square&color=#4fc08d" alt="Coverage Status" />
<img src="https://img.shields.io/npm/dm/vant.svg?style=flat-square&color=#4fc08d" alt="downloads" /> <img src="https://img.shields.io/npm/dm/vant.svg?style=flat-square&color=#4fc08d" alt="downloads" />
<img src="https://img.badgesize.io/https://unpkg.com/vant/lib/vant.min.js?compression=gzip&style=flat-square&label=gzip%20size&color=#4fc08d" alt="Gzip Size" /> <img src="https://img.badgesize.io/https://unpkg.com/vant@3/lib/vant.min.js?compression=gzip&style=flat-square&label=gzip%20size&color=#4fc08d" alt="Gzip Size" />
</p> </p>
<p align="center"> <p align="center">
@ -23,27 +24,26 @@
### 介绍 ### 介绍
Vant 是一个**轻量、可定制的移动端组件库**,于 2017 年开源。 Vant 是一个**轻量、可的移动端组件库**,于 2017 年开源。
目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant/v2)、[Vue 3 版本](https://vant-contrib.gitee.io/vant)和[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/3lang3/react-vant)和[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)。 目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant/v2)、[Vue 3 版本](https://vant-contrib.gitee.io/vant)和[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/3lang3/react-vant)和[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)。
## 特性 ## 特性
- 🚀 性能极佳,组件平均体积小于 1KBmin+gzip - 🚀 性能极佳,组件平均体积小于 1KBmin+gzip
- 🚀 80+ 个高质量组件,覆盖移动端主流场景 - 🚀 70+ 个高质量组件,覆盖移动端主流场景
- 🚀 零外部依赖,不依赖三方 npm 包 - 🚀 零外部依赖,不依赖三方 npm 包
- 💪 使用 TypeScript 编写,提供完整的类型定义 - 💪 使用 TypeScript 编写,提供完整的类型定义
- 💪 单元测试覆盖率超过 90%,提供稳定性保障 - 💪 单元测试覆盖率超过 90%,提供稳定性保障
- 📖 提供丰富的中英文文档和组件示例 - 📖 提供丰富的中英文文档和组件示例
- 📖 提供 Sketch 和 Axure 设计资源 - 📖 提供 Sketch 和 Axure 设计资源
- 🍭 支持 Vue 2、Vue 3 和微信小程序 - 🍭 支持 Vue 2、Vue 3 和微信小程序
- 🍭 支持 Nuxt 2、Nuxt 3提供 Nuxt 的 [Vant Module](https://github.com/vant-ui/vant-nuxt)
- 🍭 支持主题定制,内置 700+ 个主题变量 - 🍭 支持主题定制,内置 700+ 个主题变量
- 🍭 支持按需引入和 Tree Shaking - 🍭 支持按需引入和 Tree Shaking
- 🍭 支持无障碍访问(持续改进中) - 🍭 支持无障碍访问(持续改进中)
- 🍭 支持深色模式 - 🍭 支持深色模式(从 [Vant 4](https://vant-contrib.gitee.io/vant/v4/#/zh-CN/config-provider) 开始支持)
- 🍭 支持服务器端渲染 - 🍭 支持服务器端渲染
- 🌍 支持国际化,内置 30+ 种语言包 - 🌍 支持国际化,内置 20+ 种语言包
## 安装 ## 安装
@ -98,10 +98,9 @@ Vant 3/4 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一
| --- | --- | | --- | --- |
| [vant-weapp](https://github.com/vant-ui/vant-weapp) | Vant 微信小程序版 | | [vant-weapp](https://github.com/vant-ui/vant-weapp) | Vant 微信小程序版 |
| [vant-demo](https://github.com/vant-ui/vant-demo) | Vant 官方示例合集 | | [vant-demo](https://github.com/vant-ui/vant-demo) | Vant 官方示例合集 |
| [vant-cli](https://github.com/vant-ui/vant/tree/main/packages/vant-cli) | 开箱即用的组件库搭建工具 | | [vant-cli](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli) | 开箱即用的组件库搭建工具 |
| [vant-icons](https://github.com/vant-ui/vant/tree/main/packages/vant-icons) | Vant 图标库 | | [vant-icons](https://github.com/vant-ui/vant/tree/dev/packages/vant-icons) | Vant 图标库 |
| [vant-touch-emulator](https://github.com/vant-ui/vant/tree/main/packages/vant-touch-emulator) | 在桌面端使用 Vant 的辅助库 | | [vant-touch-emulator](https://github.com/vant-ui/vant/tree/dev/packages/vant-touch-emulator) | 在桌面端使用 Vant 的辅助库 |
| [vant-nuxt](https://github.com/vant-ui/vant-nuxt) | 为 Nuxt 准备的模块 |
## 社区生态 ## 社区生态
@ -110,6 +109,7 @@ Vant 3/4 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一
| 项目 | 描述 | | 项目 | 描述 |
| --- | --- | | --- | --- |
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | 参照 Vant 打造的 React 框架移动端组件库 | | [3lang3/react-vant](https://github.com/3lang3/react-vant) | 参照 Vant 打造的 React 框架移动端组件库 |
| [rc-ui-lib](https://github.com/rancui/rc-ui-lib) | 参照 Vant 打造的 React 框架移动端组件库 |
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Vant 支付宝小程序版 | | [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Vant 支付宝小程序版 |
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 | | [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 |
| [vant-theme](https://github.com/Aisen60/vant-theme) | Vant 在线主题预览工具 | | [vant-theme](https://github.com/Aisen60/vant-theme) | Vant 在线主题预览工具 |
@ -120,8 +120,7 @@ Vant 3/4 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一
- [详细文档](https://vant-contrib.gitee.io/vant) - [详细文档](https://vant-contrib.gitee.io/vant)
- [更新日志](https://vant-contrib.gitee.io/vant#/zh-CN/changelog) - [更新日志](https://vant-contrib.gitee.io/vant#/zh-CN/changelog)
- [码云镜像仓库](https://gitee.com/vant-contrib/vant) - [Gitter 讨论组](https://gitter.im/vant-contrib/discuss?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
- [Discussions 讨论区](https://github.com/vant-ui/vant/discussions)
## 手机预览 ## 手机预览
@ -133,13 +132,9 @@ Vant 3/4 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一
以下是 Vant 和 Vant Weapp 的核心贡献者们: 以下是 Vant 和 Vant Weapp 的核心贡献者们:
| [![chenjiahan](https://avatars.githubusercontent.com/u/7237365?s=80&v=4)](https://github.com/chenjiahan/) | [![cookfront](https://avatars.githubusercontent.com/u/4829465?s=80&v=4)](https://github.com/cookfront/) | [![w91](https://avatars.githubusercontent.com/u/2599455?s=80&v=4)](https://github.com/w91/) | [![pangxie1991](https://avatars.githubusercontent.com/u/5961240?s=80&v=4)](https://github.com/pangxie1991/) | [![rex-zsd](https://avatars.githubusercontent.com/u/8767877?s=80&v=4)](https://github.com/rex-zsd/) | [![nemo-shen](https://avatars.githubusercontent.com/u/13480805?s=80&v=4)](https://github.com/nemo-shen/) | | [![chenjiahan](https://avatars.githubusercontent.com/u/7237365?s=80&v=4)](https://github.com/chenjiahan/) | [![cookfront](https://avatars.githubusercontent.com/u/4829465?s=80&v=4)](https://github.com/cookfront/) | [![w91](https://avatars.githubusercontent.com/u/2599455?s=80&v=4)](https://github.com/w91/) | [![pangxie1991](https://avatars.githubusercontent.com/u/5961240?s=80&v=4)](https://github.com/pangxie1991/) | [![rex-zsd](https://avatars.githubusercontent.com/u/8767877?s=80&v=4)](https://github.com/rex-zsd/) | [![nemo-shen](https://avatars.githubusercontent.com/u/13480805?s=80&v=4)](https://github.com/nemo-shen/) | [![Lindysen](https://avatars.githubusercontent.com/u/33708359?s=80&v=4)](https://github.com/Lindysen/) | [![nemo-shen](https://avatars.githubusercontent.com/u/16181940?s=80&v=4)](https://github.com/JakeLaoyu/) |
| :-: | :-: | :-: | :-: | :-: | :-: | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| [chenjiahan](https://github.com/chenjiahan/) | [cookfront](https://github.com/cookfront/) | [wangnaiyi](https://github.com/w91/) | [pangxie](https://github.com/pangxie1991/) | [rex-zsd](https://github.com/rex-zsd/) | [nemo-shen](https://github.com/nemo-shen/) | | [chenjiahan](https://github.com/chenjiahan/) | [cookfront](https://github.com/cookfront/) | [wangnaiyi](https://github.com/w91/) | [pangxie](https://github.com/pangxie1991/) | [rex-zsd](https://github.com/rex-zsd/) | [nemo-shen](https://github.com/nemo-shen/) | [Lindysen](https://github.com/Lindysen/) | [JakeLaoyu](https://github.com/JakeLaoyu/) |
| [![Lindysen](https://avatars.githubusercontent.com/u/33708359?s=80&v=4)](https://github.com/Lindysen/) | [![JakeLaoyu](https://avatars.githubusercontent.com/u/16181940?s=80&v=4)](https://github.com/JakeLaoyu/) | [![landluck](https://avatars.githubusercontent.com/u/27060081?s=80&v=4)](https://github.com/landluck/) | [![wjw-gavin](https://avatars.githubusercontent.com/u/19986739?s=80&v=4)](https://github.com/wjw-gavin/) | [![inottn](https://avatars.githubusercontent.com/u/18509404?s=80&v=4)](https://github.com/inottn/) | [![zhousg](https://avatars.githubusercontent.com/u/15833290?s=80&v=4)](https://github.com/zhousg/) |
| :-: | :-: | :-: | :-: | :-: | :-: |
| [Lindysen](https://github.com/Lindysen/) | [JakeLaoyu](https://github.com/JakeLaoyu/) | [landluck](https://github.com/landluck/) | [wjw-gavin](https://github.com/wjw-gavin/) | [inottn](https://github.com/inottn/) | [zhousg](https://github.com/zhousg/) |
## 贡献者们 ## 贡献者们
@ -155,10 +150,6 @@ Vant 3/4 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一
使用过程中发现任何问题都可以提 [Issue](https://github.com/vant-ui/vant/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://github.com/vant-ui/vant/pulls)。 使用过程中发现任何问题都可以提 [Issue](https://github.com/vant-ui/vant/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://github.com/vant-ui/vant/pulls)。
## 在 Cloud IDE 中预览
[https://idegithub.com/youzan/vant](https://idegithub.com/youzan/vant)
## 开源协议 ## 开源协议
本项目基于 [MIT](https://github.com/youzan/vant/blob/main/LICENSE) 协议,请自由地享受和参与开源。 本项目基于 [MIT](https://zh.wikipedia.org/wiki/MIT%E8%A8%B1%E5%8F%AF%E8%AD%89) 协议,请自由地享受和参与开源。

View File

@ -3,10 +3,9 @@
"scripts": { "scripts": {
"prepare": "husky install", "prepare": "husky install",
"dev": "pnpm --dir ./packages/vant dev", "dev": "pnpm --dir ./packages/vant dev",
"lint": "eslint ./packages/**/src ./packages/**/test --ext .js,.ts,.tsx,.vue,.mjs,.cjs", "lint": "pnpm --dir ./packages/vant lint",
"test": "pnpm --dir ./packages/vant test", "test": "pnpm --dir ./packages/vant test",
"test:watch": "pnpm --dir ./packages/vant test:watch", "test:watch": "pnpm --dir ./packages/vant test:watch",
"test:update": "pnpm --dir ./packages/vant test:update",
"build": "pnpm --dir ./packages/vant build", "build": "pnpm --dir ./packages/vant build",
"build:site": "pnpm --dir ./packages/vant build:site" "build:site": "pnpm --dir ./packages/vant build:site"
}, },
@ -15,16 +14,24 @@
"*.{ts,tsx,js,vue,less}": "prettier --write", "*.{ts,tsx,js,vue,less}": "prettier --write",
"*.{ts,tsx,js,vue}": "eslint --fix" "*.{ts,tsx,js,vue}": "eslint --fix"
}, },
"engines": { "packageManager": "pnpm@7.11.0",
"pnpm": ">= 8.0.0"
},
"packageManager": "pnpm@8.6.5",
"devDependencies": { "devDependencies": {
"@vant/cli": "workspace:*", "@vant/cli": "workspace:*",
"@vant/eslint-config": "workspace:*", "@vant/eslint-config": "workspace:*",
"eslint": "^8.31.0", "eslint": "^8.23.0",
"husky": "^8.0.1", "husky": "^8.0.1",
"nano-staged": "^0.8.0", "nano-staged": "^0.8.0",
"prettier": "^3.0.0" "prettier": "^2.7.1",
"rimraf": "^3.0.2"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"@algolia/client-search",
"@types/react",
"react",
"react-dom"
]
}
} }
} }

View File

@ -15,5 +15,5 @@ test/coverage
es es
lib lib
dist dist
**/site-dist site
changelog.generated.md changelog.generated.md

View File

@ -28,11 +28,11 @@
"*.{ts,tsx,js,vue}": "eslint --fix" "*.{ts,tsx,js,vue}": "eslint --fix"
}, },
"peerDependencies": { "peerDependencies": {
"vue": "^3.3.4" "vue": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {
"@vant/cli": "^6.0.0", "@vant/cli": "^4.0.0",
"vue": "^3.3.4", "vue": "^3.0.0",
"sass": "^1.49.7" "sass": "^1.49.7"
}, },
"eslintConfig": { "eslintConfig": {

View File

@ -1,6 +1,6 @@
{ {
"name": "create-vant-cli-app", "name": "create-vant-cli-app",
"version": "2.2.1", "version": "2.0.1",
"description": "Create Vant CLI App", "description": "Create Vant CLI App",
"main": "lib/index.js", "main": "lib/index.js",
"bin": { "bin": {
@ -31,22 +31,22 @@
"author": "chenjiahan", "author": "chenjiahan",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^11.0.1", "@types/fs-extra": "^9.0.13",
"@types/inquirer": "^8.2.3",
"release-it": "^15.4.1", "release-it": "^15.4.1",
"rimraf": "^5.0.0", "typescript": "^4.8.2"
"typescript": "^5.0.4"
}, },
"dependencies": { "dependencies": {
"consola": "^3.0.2", "consola": "^2.11.3",
"fast-glob": "^3.2.11", "fast-glob": "^3.2.11",
"fs-extra": "^11.1.0", "fs-extra": "^10.1.0",
"enquirer": "2.3.6", "inquirer": "^8.2.4",
"picocolors": "^1.0.0" "picocolors": "^1.0.0"
}, },
"release-it": { "release-it": {
"git": { "git": {
"tag": false, "tag": false,
"commitMessage": "release: create-vant-cli-app v${version}" "commitMessage": "release: create-vant-cli-app ${version}"
} }
} }
} }

View File

@ -1,4 +1,4 @@
import { join } from 'node:path'; import { join } from 'path';
export const CWD = process.cwd(); export const CWD = process.cwd();
export const GENERATOR_DIR = join(__dirname, '../generators'); export const GENERATOR_DIR = join(__dirname, '../generators');

View File

@ -1,31 +1,31 @@
import fs from 'fs-extra'; import fs from 'fs-extra';
import glob from 'fast-glob'; import glob from 'fast-glob';
import color from 'picocolors'; import color from 'picocolors';
import { consola } from 'consola'; import consola from 'consola';
import { prompt } from 'enquirer'; import { prompt } from 'inquirer';
import { sep, join } from 'node:path'; import { sep, join } from 'path';
import { CWD, GENERATOR_DIR } from './constant'; import { CWD, GENERATOR_DIR } from './constant';
const PROMPTS = [ const PROMPTS = [
{ {
name: 'vueVersion', name: 'vueVersion',
message: 'Select Vue version', message: 'Select Vue version',
type: 'select', type: 'list',
choices: [ choices: [
{ {
name: 'vue2', name: 'Vue 2',
message: 'Vue 2', value: 'vue2',
}, },
{ {
name: 'vue3', name: 'Vue 3',
message: 'Vue 3', value: 'vue3',
}, },
], ],
}, },
{ {
name: 'preprocessor', name: 'preprocessor',
message: 'Select css preprocessor', message: 'Select css preprocessor',
type: 'select', type: 'list',
choices: ['Less', 'Sass'], choices: ['Less', 'Sass'],
}, },
]; ];
@ -69,14 +69,14 @@ export class VanGenerator {
// see https://github.com/mrmlnc/fast-glob#how-to-write-patterns-on-windows // see https://github.com/mrmlnc/fast-glob#how-to-write-patterns-on-windows
const templatePath = join(GENERATOR_DIR, this.inputs.vueVersion).replace( const templatePath = join(GENERATOR_DIR, this.inputs.vueVersion).replace(
/\\/g, /\\/g,
'/', '/'
); );
const templateFiles = glob.sync( const templateFiles = glob.sync(
join(templatePath, '**', '*').replace(/\\/g, '/'), join(templatePath, '**', '*').replace(/\\/g, '/'),
{ {
dot: true, dot: true,
}, }
); );
templateFiles.forEach((filePath) => { templateFiles.forEach((filePath) => {
@ -109,8 +109,8 @@ export class VanGenerator {
consola.success(`Successfully created ${color.yellow(name)}.`); consola.success(`Successfully created ${color.yellow(name)}.`);
consola.success( consola.success(
`Run ${color.yellow( `Run ${color.yellow(
`cd ${name} && git init && yarn && yarn dev`, `cd ${name} && git init && yarn && yarn dev`
)} to start development!`, )} to start development!`
); );
} }
} }

View File

@ -1,16 +1,20 @@
#!/usr/bin/env node #!/usr/bin/env node
import { consola } from 'consola'; import consola from 'consola';
import { prompt } from 'enquirer'; import { prompt } from 'inquirer';
import { ensureDir } from 'fs-extra'; import { ensureDir } from 'fs-extra';
import { VanGenerator } from './generator'; import { VanGenerator } from './generator';
async function run() { const PROMPTS = [
const { name } = await prompt<{ name: string }>({ {
type: 'input', type: 'input',
name: 'name', name: 'name',
message: 'Your package name', message: 'Your package name',
}); },
];
async function run() {
const { name } = await prompt(PROMPTS);
try { try {
await ensureDir(name); await ensureDir(name);

View File

@ -6,6 +6,5 @@
"module": "commonjs", "module": "commonjs",
"declaration": true "declaration": true
}, },
"include": ["src/**/*"], "include": ["src/**/*"]
"exclude": ["**/node_modules", "**/.*/"]
} }

View File

@ -1,6 +1,6 @@
# Vant China Area Data # Vant Area Data
中国省市区数据,适用于 Vant Area 和 Cascader 等组件。 中国省市区数据,适用于 Vant Area 组件。
## 安装 ## 安装
@ -17,20 +17,10 @@ pnpm add @vant/area-data
## 使用 ## 使用
在 Vant 的 Area 组件中使用时,直接引用 `areaList` 对象即可:
```ts ```ts
import { areaList } from '@vant/area-data'; import { areaList } from '@vant/area-data';
``` ```
在 Vant 的 Cascader 组件中使用时,请使用 `useCascaderAreaData` 方法:
```ts
import { useCascaderAreaData } from '@vant/area-data';
const cascaderAreaData = useCascaderAreaData();
```
## 数据更新 ## 数据更新
中国的行政区划每年都会有变动,如果发现省市区数据未及时更新,欢迎提 Pull Request 帮助我们更新。你可以在[「国家统计局 - 全国区划代码」](http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/) 和[「民政部 - 行政区划代码」](https://www.mca.gov.cn/article/sj/xzqh/1980/)上查询到最新数据,请根据官方数据进行核实。 中国的行政区划每年都会有变动,如果发现省市区数据未及时更新,欢迎提 Pull Request 帮助我们更新。

View File

@ -1,6 +1,6 @@
{ {
"name": "@vant/area-data", "name": "@vant/area-data",
"version": "1.4.1", "version": "1.3.2",
"description": "Vant 省市区数据", "description": "Vant 省市区数据",
"main": "dist/index.cjs.js", "main": "dist/index.cjs.js",
"module": "dist/index.esm.mjs", "module": "dist/index.esm.mjs",
@ -11,7 +11,6 @@
"require": "./dist/index.cjs.js" "require": "./dist/index.cjs.js"
} }
}, },
"sideEffects": false,
"files": [ "files": [
"dist" "dist"
], ],
@ -37,15 +36,14 @@
"author": "chenjiahan", "author": "chenjiahan",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"esbuild": "^0.18.11", "esbuild": "^0.14.54",
"release-it": "^15.4.1", "release-it": "^15.4.1",
"rimraf": "^5.0.0", "typescript": "^4.8.2"
"typescript": "^5.0.4"
}, },
"release-it": { "release-it": {
"git": { "git": {
"tag": false, "tag": false,
"commitMessage": "release: @vant/area-data v${version}" "commitMessage": "release: @vant/area-data ${version}"
} }
} }
} }

View File

@ -1,8 +1,4 @@
export const areaList: { export const areaList = {
province_list: Record<string, string>;
city_list: Record<string, string>;
county_list: Record<string, string>;
} = {
province_list: { province_list: {
110000: '北京市', 110000: '北京市',
120000: '天津市', 120000: '天津市',
@ -1625,6 +1621,7 @@ export const areaList: {
360724: '上犹县', 360724: '上犹县',
360725: '崇义县', 360725: '崇义县',
360726: '安远县', 360726: '安远县',
360727: '龙南县',
360728: '定南县', 360728: '定南县',
360729: '全南县', 360729: '全南县',
360730: '宁都县', 360730: '宁都县',
@ -1634,7 +1631,6 @@ export const areaList: {
360734: '寻乌县', 360734: '寻乌县',
360735: '石城县', 360735: '石城县',
360781: '瑞金市', 360781: '瑞金市',
360783: '龙南市',
360802: '吉州区', 360802: '吉州区',
360803: '青原区', 360803: '青原区',
360821: '吉安县', 360821: '吉安县',
@ -3890,53 +3886,3 @@ export const areaList: {
820204: '圣方济各堂区', 820204: '圣方济各堂区',
}, },
}; };
type CascaderOption = {
text: string;
value: string;
children?: CascaderOption[];
};
const makeOption = (
text: string,
value: string,
children?: CascaderOption[],
): CascaderOption => ({
text,
value,
children,
});
export function useCascaderAreaData() {
const {
city_list: city,
county_list: county,
province_list: province,
} = areaList;
const provinceMap = new Map<string, CascaderOption>();
Object.keys(province).forEach((code) => {
provinceMap.set(code.slice(0, 2), makeOption(province[code], code, []));
});
const cityMap = new Map<string, CascaderOption>();
Object.keys(city).forEach((code) => {
const option = makeOption(city[code], code, []);
cityMap.set(code.slice(0, 4), option);
const province = provinceMap.get(code.slice(0, 2));
if (province) {
province.children!.push(option);
}
});
Object.keys(county).forEach((code) => {
const city = cityMap.get(code.slice(0, 4));
if (city) {
city.children!.push(makeOption(county[code], code));
}
});
return Array.from(provinceMap.values());
}

View File

@ -4,6 +4,5 @@
"outDir": "./dist", "outDir": "./dist",
"declaration": true "declaration": true
}, },
"include": ["src/**/*"], "include": ["src/**/*"]
"exclude": ["**/node_modules", "**/.*/"]
} }

View File

@ -0,0 +1,8 @@
{
"root": true,
"extends": ["@vant"],
"rules": {
"global-require": 0,
"import/no-dynamic-require": 0
}
}

View File

@ -65,7 +65,7 @@ Please add the followed config to `package.json` file.
## More Details ## More Details
- [cli](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/commands.md) - [cli](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/commands.md)
- [config](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/config.md) - [config](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/config.md)
- [directory structure](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/directory.md) - [directory structure](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/directory.md)
- [CHANGELOG](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/changelog.md) - [CHANGELOG](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/changelog.md)

View File

@ -62,7 +62,7 @@ pnpm add @vant/cli -D
## 详细文档 ## 详细文档
- [命令](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/commands.zh-CN.md) - [命令](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/commands.zh-CN.md)
- [配置指南](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/config.zh-CN.md) - [配置指南](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/config.zh-CN.md)
- [目录结构](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/directory.zh-CN.md) - [目录结构](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/directory.zh-CN.md)
- [更新日志](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/changelog.md) - [更新日志](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/changelog.md)

View File

@ -1,61 +1,14 @@
# 更新日志 # 更新日志
## v6.1.0 ## v5.0.0 (未发布)
`2023-03-19`
- 升级 typescript v5
- 升级 esbuild 0.17
- 升级 vite 4.2
- 优化 tsc 错误日志的格式
## v6.0.1
`2023-03-11`
- 修复编译 `mjs` 或者 `cjs` 时, 替换 vue 文件导入出现重复后缀的问题
## v6.0.0
`2023-02-26`
- vite: 由 v3 升级至 v4
- @vitejs/plugin-vue: 由 v3 升级至 v4
- @vitejs/plugin-vue-jsx: 由 v2 升级至 v3
- 移除 `site.searchConfig` 配置项
- 修复 build 时解析 markdown 可能报错的问题
## v5.1.0
`2022-11-05`
- 支持读取 `vite.config.ts` 文件来自定义 vite 配置
- 修复设置 vite 的 `server.port` 配置项不生效的问题
## v5.0.2
`2022-10-07`
- 修复首次运行 dev 时 vite 引入了两份 Vue 代码导致渲染失败的问题
## v5.0.1
`2022-10-06`
- 修复 jest 版本未正确升级的问题
## v5.0.0
### 依赖升级 ### 依赖升级
`2022-10-06`
对以下依赖进行了大版本升级: 对以下依赖进行了大版本升级:
- vite: 由 v2 升级至 v3 - vite v3
- jest: 由 v27 升级至 v29 - @vitejs/plugin-vue v3
- @vitejs/plugin-vue: 由 v2 升级至 v3 - @vitejs/plugin-vue-jsx v2
- @vitejs/plugin-vue-jsx: 由 v1 升级至 v2
### 依赖精简 ### 依赖精简

View File

@ -29,10 +29,6 @@ const DEFAULT_CONFIG = {
], ],
coverageReporters: ['html', 'lcov', 'text-summary'], coverageReporters: ['html', 'lcov', 'text-summary'],
coverageDirectory: './test/coverage', coverageDirectory: './test/coverage',
testEnvironmentOptions: {
// https://stackoverflow.com/questions/72428323/jest-referenceerror-vue-is-not-defined
customExportConditions: ['node', 'node-addons'],
},
}; };
function readRootConfig() { function readRootConfig() {

View File

@ -35,7 +35,7 @@ const transformSFC = (code, path) => {
if (descriptor.script) { if (descriptor.script) {
const content = descriptor.script.content.replace( const content = descriptor.script.content.replace(
'export default', 'export default',
'const script =', 'const script ='
); );
output.push(content); output.push(content);
} else if (descriptor.scriptSetup) { } else if (descriptor.scriptSetup) {
@ -87,8 +87,6 @@ module.exports = {
if (isJsxFile(path)) { if (isJsxFile(path)) {
code = transformJsx(code, path); code = transformJsx(code, path);
} }
return { return transformScript(code);
code: transformScript(code),
};
}, },
}; };

View File

@ -14,13 +14,11 @@ function getPostcssPlugins(rootConfig) {
const plugins = rootConfig.plugins || []; const plugins = rootConfig.plugins || [];
if (Array.isArray(plugins)) { if (Array.isArray(plugins)) {
const hasAutoprefixerPlugin = plugins.find((plugin) => { const hasPostcssPlugin = plugins.find(
if (typeof plugin === 'object') { (plugin) =>
return plugin.postcssPlugin === 'autoprefixer'; plugin === 'autoprefixer' && plugin.postcssPlugin === 'autoprefixer'
} );
return plugin === 'autoprefixer'; if (hasPostcssPlugin) {
});
if (hasAutoprefixerPlugin) {
return plugins; return plugins;
} }

View File

@ -29,7 +29,7 @@ Start local dev server for browsering components and demo.
Build Vue component library. Build Vue component library.
Files will be output to `es` and `lib` directory. More details [directory structure](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/directory.md) Files will be output to `es` and `lib` directory. More details [directory structure](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/directory.md)
Please add the followed config to `package.json` when publish to npm. Please add the followed config to `package.json` when publish to npm.

View File

@ -31,7 +31,7 @@ npx vant-cli dev
构建组件库。 构建组件库。
运行 build 命令会在 `es``lib` 目录下生成可用于生产环境的组件代码,详见 [目录结构](https://github.com/vant-ui/vant/tree/main/packages/vant-cli/docs/directory.zh-CN.md)。 运行 build 命令会在 `es``lib` 目录下生成可用于生产环境的组件代码,详见 [目录结构](https://github.com/vant-ui/vant/tree/dev/packages/vant-cli/docs/directory.zh-CN.md)。
发布 npm 时,请将以下配置加入到 `package.json` 中,使 npm 包能被正确识别: 发布 npm 时,请将以下配置加入到 `package.json` 中,使 npm 包能被正确识别:

View File

@ -16,6 +16,7 @@
- [site.nav](#sitenav) - [site.nav](#sitenav)
- [site.versions](#siteversions) - [site.versions](#siteversions)
- [site.baiduAnalytics](#sitebaiduanalytics) - [site.baiduAnalytics](#sitebaiduanalytics)
- [site.searchConfig](#sitesearchconfig)
- [site.hideSimulator](#sitehidesimulator) - [site.hideSimulator](#sitehidesimulator)
- [site.simulator.url](#sitesimulatorurl) - [site.simulator.url](#sitesimulatorurl)
- [site.htmlMeta](#sitehtmlmeta) - [site.htmlMeta](#sitehtmlmeta)
@ -176,16 +177,17 @@ When set to `true`, `export * from 'xxx'` will be used to export all modules and
### build.configureVite ### build.configureVite
- Type: `(config: InlineConfig): InlineConfig | undefined` - Type: `(config: InlineConfig): InlineConfig`
- Default: `undefined` - Default: `undefined`
Custom [vite config](https://vitejs.dev/config/), requires `@vant/cli>= 4.0.0`. Custom vite config(`@vant/cli>= 4.0.0`)
```js ```js
module.exports = { module.exports = {
build: { build: {
configureVite(config) { configureVite(config) {
config.server.port = 3000; // add vite plugin
config.plugins.push(vitePluginXXX);
return config; return config;
}, },
}, },
@ -212,14 +214,10 @@ module.exports = {
}; };
``` ```
Note that you are not allowed to import vite plugins in `vant.config.mjs`, because the file will be bundled into the website code.
If you need to configure some vite plugins, please create a `vite.config.ts` file in the same directory of `vant.config.mjs`, in which you can add any vite configuration (this feature requires @vant/cli 5.1.0).
### build.packageManager ### build.packageManager
- Type: `'npm' | 'yarn' | 'pnpm'` - Type: `'npm' | 'yarn' | 'pnpm'`
- Default: `yarn` - Default: `undefined`
`npm` package manager. `npm` package manager.
@ -354,6 +352,13 @@ module.exports = {
}; };
``` ```
### site.searchConfig
- Type: `object`
- Default: `undefined`
Documentation site search config. Based on [docsearch](https://docsearch.algolia.com/docs/behavior) of algolia.
### site.hideSimulator ### site.hideSimulator
- Type: `boolean` - Type: `boolean`

View File

@ -16,6 +16,7 @@
- [site.nav](#sitenav) - [site.nav](#sitenav)
- [site.versions](#siteversions) - [site.versions](#siteversions)
- [site.baiduAnalytics](#sitebaiduanalytics) - [site.baiduAnalytics](#sitebaiduanalytics)
- [site.searchConfig](#sitesearchconfig)
- [site.hideSimulator](#sitehidesimulator) - [site.hideSimulator](#sitehidesimulator)
- [site.simulator.url](#sitesimulatorurl) - [site.simulator.url](#sitesimulatorurl)
- [site.htmlMeta](#sitehtmlmeta) - [site.htmlMeta](#sitehtmlmeta)
@ -176,16 +177,17 @@ module.exports = {
### build.configureVite ### build.configureVite
- Type: `(config: InlineConfig): InlineConfig | undefined` - Type: `(config: InlineConfig): InlineConfig`
- Default: `undefined` - Default: `undefined`
vant-cli 使用 vite 来构建组件库和文档站点,通过 `configureVite` 选项可以自定义 [vite 配置](https://vitejs.dev/config/)(从 4.0.0 版本开始支持)。 vant-cli 使用 vite 来构建组件库和文档站点,通过 `configureVite` 选项可以自定义 vite 配置(从 4.0.0 版本开始支持)。
```js ```js
module.exports = { module.exports = {
build: { build: {
configureVite(config) { configureVite(config) {
config.server.port = 3000; // 添加一个自定义插件
config.plugins.push(vitePluginXXX);
return config; return config;
}, },
}, },
@ -214,14 +216,10 @@ module.exports = {
}; };
``` ```
注意,由于 `vant.config.mjs` 文件会被打包到文档网站的代码中,因此 `configureVite` 中不允许引用 vite 插件。
如果需要配置 vite 插件,可以在 `vant.config.mjs` 的同级目录下创建 `vite.config.ts` 文件,在该文件中你可以添加任意的 vite 配置(该特性从 @vant/cli 5.1.0 版本开始支持)。
### build.packageManager ### build.packageManager
- Type: `'npm' | 'yarn' | 'pnpm'` - Type: `'npm' | 'yarn' | 'pnpm'`
- Default: `yarn` - Default: `undefined`
指定使用的包管理器。 指定使用的包管理器。
@ -356,6 +354,15 @@ module.exports = {
}; };
``` ```
### site.searchConfig
- Type: `object`
- Default: `undefined`
文档网站的搜索配置,基于 algolia 提供的 docsearch 服务实现。
配置内容参见 [docsearch](https://docsearch.algolia.com/docs/behavior)。
### site.hideSimulator ### site.hideSimulator
- Type: `boolean` - Type: `boolean`

View File

@ -1,6 +1,6 @@
{ {
"name": "@vant/cli", "name": "@vant/cli",
"version": "6.1.0", "version": "4.0.4",
"type": "module", "type": "module",
"main": "lib/index.js", "main": "lib/index.js",
"typings": "lib/index.d.ts", "typings": "lib/index.d.ts",
@ -39,61 +39,61 @@
"author": "chenjiahan", "author": "chenjiahan",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@jest/types": "^29.1.2", "@jest/types": "^27.5.1",
"@types/fs-extra": "^11.0.1", "@types/fs-extra": "^9.0.13",
"@types/less": "^3.0.3", "@types/less": "^3.0.3",
"@types/lodash": "^4.14.191",
"@types/markdown-it": "^12.2.3", "@types/markdown-it": "^12.2.3",
"rimraf": "^5.0.0", "react": "^18.2.0",
"vue": "^3.3.4" "react-dom": "^18.2.0",
"vue": "^3.2.38"
}, },
"dependencies": { "dependencies": {
"@babel/core": "^7.18.13", "@babel/core": "^7.18.13",
"@babel/preset-typescript": "^7.18.6", "@babel/preset-typescript": "^7.18.6",
"@types/jest": "^29.5.1", "@docsearch/css": "^3.2.1",
"@vant/eslint-config": "^4.0.0", "@docsearch/js": "^3.2.1",
"@types/jest": "^27.5.2",
"@vant/eslint-config": "^3.5.0",
"@vant/touch-emulator": "^1.4.0", "@vant/touch-emulator": "^1.4.0",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^3.0.3",
"@vitejs/plugin-vue-jsx": "^3.0.0", "@vitejs/plugin-vue-jsx": "^2.0.1",
"@vue/babel-plugin-jsx": "^1.1.1", "@vue/babel-plugin-jsx": "^1.1.1",
"autoprefixer": "^10.4.8", "autoprefixer": "^10.4.8",
"commander": "^10.0.0", "commander": "^9.4.0",
"consola": "^3.0.2", "consola": "^2.15.3",
"conventional-changelog": "^3.1.25", "conventional-changelog": "^3.1.25",
"esbuild": "^0.18.11", "esbuild": "^0.14.54",
"eslint": "^8.31.0", "eslint": "^8.23.0",
"execa": "^6.1.0", "execa": "^5.1.1",
"fast-glob": "^3.2.11", "fast-glob": "^3.2.11",
"fs-extra": "^11.1.0", "fs-extra": "^10.1.0",
"hash-sum": "^2.0.0", "hash-sum": "^2.0.0",
"highlight.js": "^11.6.0", "highlight.js": "^11.6.0",
"husky": "^8.0.1", "husky": "^8.0.1",
"jest": "^29.5.0", "jest": "^27.5.1",
"jest-canvas-mock": "^2.4.0", "jest-canvas-mock": "^2.4.0",
"jest-environment-jsdom": "^29.1.2",
"jest-serializer-html": "^7.1.0", "jest-serializer-html": "^7.1.0",
"less": "^4.1.3", "less": "^4.1.3",
"lodash": "^4.17.21",
"markdown-it": "^12.3.2", "markdown-it": "^12.3.2",
"markdown-it-anchor": "^8.6.4", "markdown-it-anchor": "^8.6.4",
"nano-staged": "^0.8.0", "nano-staged": "^0.8.0",
"nanospinner": "^1.1.0", "nanospinner": "^1.1.0",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"postcss": "^8.4.23", "postcss": "^8.4.16",
"postcss-load-config": "^4.0.1", "postcss-load-config": "^3.1.4",
"prettier": "^3.0.0", "prettier": "^2.7.1",
"release-it": "^15.4.1", "release-it": "^15.4.1",
"terser": "^5.16.1",
"transliteration": "^2.3.5", "transliteration": "^2.3.5",
"typescript": "^5.0.4", "typescript": "^4.8.2",
"vite": "^4.4.2", "vite": "^3.0.9",
"vite-plugin-html": "^2.1.2",
"vite-plugin-md": "^0.11.9", "vite-plugin-md": "^0.11.9",
"vue-router": "^4.1.6" "vue-router": "^4.1.5"
}, },
"release-it": { "release-it": {
"git": { "git": {
"tag": false, "tag": false,
"commitMessage": "release: @vant/cli v${version}" "commitMessage": "release: @vant/cli ${version}"
} }
} }
} }

View File

@ -40,7 +40,7 @@ export function syncPathToParent() {
type: 'replacePath', type: 'replacePath',
value: getCurrentDir(), value: getCurrentDir(),
}, },
'*', '*'
); );
} }
@ -53,7 +53,7 @@ export function syncPathToChild() {
type: 'replacePath', type: 'replacePath',
value: getCurrentDir(), value: getCurrentDir(),
}, },
'*', '*'
); );
}); });
} }
@ -68,7 +68,7 @@ export function syncThemeToChild(theme) {
type: 'updateTheme', type: 'updateTheme',
value: theme, value: theme,
}, },
'*', '*'
); );
}); });
} }

View File

@ -6,20 +6,9 @@ body {
overflow-x: auto; overflow-x: auto;
color: var(--van-doc-text-color-2); color: var(--van-doc-text-color-2);
font-size: 16px; font-size: 16px;
font-family: font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
'Open Sans', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui',
-apple-system, 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
BlinkMacSystemFont,
'Helvetica Neue',
Helvetica,
Segoe UI,
Arial,
Roboto,
'PingFang SC',
'miui',
'Hiragino Sans GB',
'Microsoft Yahei',
sans-serif;
background-color: var(--van-doc-background); background-color: var(--van-doc-background);
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }

View File

@ -6,7 +6,7 @@ code {
color: var(--van-doc-code-color); color: var(--van-doc-code-color);
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
font-family: var(--van-doc-code-font-family); font-family: 'Source Code Pro', 'Monaco', 'Inconsolata', monospace;
line-height: 26px; line-height: 26px;
white-space: pre-wrap; white-space: pre-wrap;
word-wrap: break-word; word-wrap: break-word;
@ -15,13 +15,6 @@ code {
border-radius: var(--van-doc-border-radius); border-radius: var(--van-doc-border-radius);
} }
p {
code {
display: inline-flex;
padding: 4px 10px;
}
}
pre { pre {
margin: 20px 0 0; margin: 20px 0 0;

View File

@ -1,4 +1,4 @@
:root { body {
// colors // colors
--van-doc-black: #000; --van-doc-black: #000;
--van-doc-white: #fff; --van-doc-white: #fff;
@ -12,20 +12,15 @@
--van-doc-gray-8: #323233; --van-doc-gray-8: #323233;
--van-doc-blue: #1989fa; --van-doc-blue: #1989fa;
--van-doc-green: #07c160; --van-doc-green: #07c160;
--van-doc-purple: #8e69d3;
// sizes // sizes
--van-doc-padding: 32px; --van-doc-padding: 24px;
--van-doc-row-max-width: 1680px; --van-doc-row-max-width: 1680px;
--van-doc-nav-width: 220px; --van-doc-nav-width: 220px;
--van-doc-border-radius: 20px; --van-doc-border-radius: 20px;
--van-doc-simulator-width: 360px; --van-doc-simulator-width: 360px;
--van-doc-simulator-height: 620px; --van-doc-simulator-height: 620px;
--van-doc-header-top-height: 64px; --van-doc-header-top-height: 64px;
// fonts
--van-doc-code-font-family: 'Menlo', 'Source Code Pro', 'Monaco',
'Inconsolata', monospace;
} }
.van-doc-theme-light { .van-doc-theme-light {
@ -49,7 +44,7 @@
--van-doc-code-background: var(--van-doc-gray-1); --van-doc-code-background: var(--van-doc-gray-1);
// blockquote // blockquote
--van-doc-blockquote-color: #2f85da; --van-doc-blockquote-color: #4994df;
--van-doc-blockquote-background: #ecf9ff; --van-doc-blockquote-background: #ecf9ff;
} }

View File

@ -107,11 +107,11 @@ export default {
const navItems = this.config.nav.reduce( const navItems = this.config.nav.reduce(
(result, nav) => [...result, ...nav.items], (result, nav) => [...result, ...nav.items],
[], []
); );
const current = navItems.find( const current = navItems.find(
(item) => item.path === this.$route.meta.name, (item) => item.path === this.$route.meta.name
); );
if (current && current.title) { if (current && current.title) {

View File

@ -12,11 +12,6 @@ import { copyToClipboard } from '../../common';
export default { export default {
name: 'VanDocContent', name: 'VanDocContent',
data() {
return {
iframeDocument: null,
};
},
computed: { computed: {
currentPage() { currentPage() {
@ -55,22 +50,6 @@ export default {
name: this.$route.name, name: this.$route.name,
hash: '#' + target.id, hash: '#' + target.id,
}); });
this.syncMobilePos(target.id);
}
},
syncMobilePos(id) {
// Getting the document at this point is to ensure that the target has been fully rendered.
if (!this.iframeDocument) {
const iframe = document.querySelector('iframe');
this.iframeDocument = iframe.contentWindow.document;
}
if (this.iframeDocument) {
const target = this.iframeDocument.getElementById(id);
if (target) {
target.scrollIntoView(true);
}
} }
}, },
@ -104,8 +83,8 @@ export default {
<style lang="less"> <style lang="less">
.van-doc-card { .van-doc-card {
margin-bottom: var(--van-doc-padding); margin-bottom: 24px;
padding: 28px 28px 32px; padding: 24px;
background-color: var(--van-doc-background-2); background-color: var(--van-doc-background-2);
border-radius: var(--van-doc-border-radius); border-radius: var(--van-doc-border-radius);
overflow: auto; overflow: auto;
@ -206,7 +185,7 @@ export default {
} }
> p { > p {
margin-top: 16px; margin-top: 8px;
color: var(--van-doc-text-color-3); color: var(--van-doc-text-color-3);
font-size: 15px; font-size: 15px;
line-height: 26px; line-height: 26px;
@ -266,7 +245,7 @@ export default {
display: inline-block; display: inline-block;
color: var(--van-doc-green); color: var(--van-doc-green);
font-size: 14px; font-size: 14px;
font-family: var(--van-doc-code-font-family); font-family: 'Source Code Pro', 'Monaco', 'Inconsolata', monospace;
font-style: normal; font-style: normal;
max-width: 300px; max-width: 300px;
-webkit-font-smoothing: auto; -webkit-font-smoothing: auto;
@ -274,7 +253,7 @@ export default {
} }
> ul { > ul {
margin: 16px 0 0; margin: 12px 0;
} }
> ul li, > ul li,
@ -312,19 +291,19 @@ export default {
> table code { > table code {
display: inline; display: inline;
margin: 0 2px; margin: 0 2px;
padding: 3px 7px; padding: 2px 5px;
font-size: 14px; font-size: 14px;
font-family: inherit;
font-weight: 600;
word-break: keep-all; word-break: keep-all;
border-radius: 6px; border-radius: 4px;
-webkit-font-smoothing: auto; -webkit-font-smoothing: antialiased;
font-family: var(--van-doc-code-font-family);
} }
> blockquote { > blockquote {
margin: 16px 0 0; margin: 16px 0 0;
padding: 16px; padding: 16px;
font-size: 15px; font-size: 14px;
line-height: 26px;
color: var(--van-doc-blockquote-color); color: var(--van-doc-blockquote-color);
background-color: var(--van-doc-blockquote-background); background-color: var(--van-doc-blockquote-background);
border-radius: var(--van-doc-border-radius); border-radius: var(--van-doc-border-radius);
@ -333,7 +312,7 @@ export default {
> img, > img,
> p img { > p img {
width: 100%; width: 100%;
margin: 16px 0 0; margin: 16px 0;
border-radius: var(--van-doc-border-radius); border-radius: var(--van-doc-border-radius);
} }
} }
@ -344,7 +323,7 @@ export default {
padding: 0 0 75px; padding: 0 0 75px;
.van-doc-markdown-body { .van-doc-markdown-body {
padding: var(--van-doc-padding); padding: 24px;
overflow: hidden; overflow: hidden;
h1, h1,
@ -364,7 +343,7 @@ export default {
} }
h2 { h2 {
margin: 52px 0 20px; margin: 45px 0 20px;
font-size: 26px; font-size: 26px;
} }
} }

View File

@ -108,9 +108,7 @@ export default {
cursor: pointer; cursor: pointer;
opacity: 0.6; opacity: 0.6;
outline: none; outline: none;
transition: transition: opacity 0.2s, background 0.2s;
opacity 0.2s,
background 0.2s;
// expand click area // expand click area
&::after { &::after {

View File

@ -64,6 +64,12 @@
{{ langLabel }} {{ langLabel }}
</a> </a>
</li> </li>
<search-input
v-if="searchConfig"
:lang="lang"
:search-config="searchConfig"
/>
</ul> </ul>
</div> </div>
</div> </div>
@ -71,12 +77,17 @@
</template> </template>
<script> <script>
import SearchInput from './SearchInput.vue';
import { packageVersion } from 'site-desktop-shared'; import { packageVersion } from 'site-desktop-shared';
import { getDefaultTheme, syncThemeToChild } from '../../common/iframe-sync'; import { getDefaultTheme, syncThemeToChild } from '../../common/iframe-sync';
export default { export default {
name: 'VanDocHeader', name: 'VanDocHeader',
components: {
SearchInput,
},
props: { props: {
lang: String, lang: String,
config: Object, config: Object,
@ -111,6 +122,10 @@ export default {
return {}; return {};
}, },
searchConfig() {
return this.config.searchConfig;
},
themeImg() { themeImg() {
if (this.currentTheme === 'light') { if (this.currentTheme === 'light') {
return 'https://b.yzcdn.cn/vant/dark-theme.svg'; return 'https://b.yzcdn.cn/vant/dark-theme.svg';
@ -123,8 +138,8 @@ export default {
currentTheme: { currentTheme: {
handler(newVal, oldVal) { handler(newVal, oldVal) {
window.localStorage.setItem('vantTheme', newVal); window.localStorage.setItem('vantTheme', newVal);
document.documentElement.classList.remove(`van-doc-theme-${oldVal}`); document.body.classList.remove(`van-doc-theme-${oldVal}`);
document.documentElement.classList.add(`van-doc-theme-${newVal}`); document.body.classList.add(`van-doc-theme-${newVal}`);
syncThemeToChild(newVal); syncThemeToChild(newVal);
}, },
immediate: true, immediate: true,
@ -142,7 +157,7 @@ export default {
const action = val ? 'add' : 'remove'; const action = val ? 'add' : 'remove';
document.body[`${action}EventListener`]( document.body[`${action}EventListener`](
'click', 'click',
this.checkHideVersionPop, this.checkHideVersionPop
); );
this.showVersionPop = val; this.showVersionPop = val;
@ -172,8 +187,6 @@ export default {
width: 100%; width: 100%;
background-color: var(--van-doc-header-background); background-color: var(--van-doc-header-background);
user-select: none; user-select: none;
position: relative;
z-index: 2;
&__top { &__top {
display: flex; display: flex;

View File

@ -1,5 +1,5 @@
<template> <template>
<div :class="['van-doc-nav', { 'van-doc-nav-fixed': isFixed }]"> <div class="van-doc-nav" :style="style">
<div <div
v-for="(group, index) in navConfig" v-for="(group, index) in navConfig"
class="van-doc-nav__group" class="van-doc-nav__group"
@ -38,11 +38,19 @@ export default {
data() { data() {
return { return {
isFixed: false, top: 64,
bottom: 0,
}; };
}, },
computed: { computed: {
style() {
return {
top: this.top + 'px',
bottom: this.bottom + 'px',
};
},
base() { base() {
return this.lang ? `/${this.lang}/` : '/'; return this.lang ? `/${this.lang}/` : '/';
}, },
@ -56,7 +64,7 @@ export default {
methods: { methods: {
onScroll() { onScroll() {
const { pageYOffset: offset } = window; const { pageYOffset: offset } = window;
this.isFixed = offset > 64; this.top = Math.max(0, 64 - offset);
}, },
}, },
}; };
@ -64,10 +72,8 @@ export default {
<style lang="less"> <style lang="less">
.van-doc-nav { .van-doc-nav {
position: absolute; position: fixed;
left: 0; left: 0;
top: var(--van-doc-header-top-height);
bottom: 0;
z-index: 1; z-index: 1;
min-width: var(--van-doc-nav-width); min-width: var(--van-doc-nav-width);
max-width: var(--van-doc-nav-width); max-width: var(--van-doc-nav-width);
@ -80,10 +86,6 @@ export default {
margin-left: calc((var(--van-doc-row-max-width) / 2 * -1)); margin-left: calc((var(--van-doc-row-max-width) / 2 * -1));
} }
&.van-doc-nav-fixed {
position: fixed;
top: 0;
}
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 6px; width: 6px;
height: 6px; height: 6px;
@ -108,14 +110,14 @@ export default {
padding: 24px 0 0 var(--van-doc-padding); padding: 24px 0 0 var(--van-doc-padding);
color: var(--van-doc-text-color-2); color: var(--van-doc-text-color-2);
font-weight: 600; font-weight: 600;
font-size: 16px; font-size: 15px;
line-height: 28px; line-height: 28px;
} }
&__item { &__item {
a { a {
display: block; display: block;
margin: 4px 0; margin: 8px 0;
padding: 6px 0 6px var(--van-doc-padding); padding: 6px 0 6px var(--van-doc-padding);
color: var(--van-doc-text-color-3); color: var(--van-doc-text-color-3);
font-size: 14px; font-size: 14px;

View File

@ -0,0 +1,63 @@
<template>
<div id="docsearch" />
</template>
<script>
export default {
name: 'VanDocSearch',
props: {
lang: String,
searchConfig: Object,
},
watch: {
lang() {
this.initDocsearch();
},
},
mounted() {
this.initDocsearch();
},
methods: {
initDocsearch() {
if (this.searchConfig) {
import('@docsearch/css');
import('@docsearch/js').then((docsearch) => {
docsearch.default({
...this.searchConfig,
container: '#docsearch',
});
});
}
},
},
};
</script>
<style lang="less">
#docsearch {
display: inline-block;
vertical-align: middle;
}
.DocSearch-Button {
height: 32px;
background: #f7f8fa;
&:hover {
box-shadow: none;
}
}
.DocSearch-Search-Icon {
width: 18px;
height: 18px;
}
.DocSearch-Button-Key {
font-size: 12px;
}
</style>

View File

@ -1,4 +1,4 @@
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
@ -11,11 +11,14 @@
name="viewport" name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/> />
<%= meta %> <%- meta %>
<meta http-equiv="Cache-Control" content="no-cache" /> <meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" /> <meta http-equiv="Expires" content="0" />
<% if (headHtml) { %> <%= headHtml %> <% } %> <% if (baiduAnalytics) { %> <% if (headHtml) { %>
<%- headHtml %>
<% } %>
<% if (baiduAnalytics) { %>
<script> <script>
var _hmt = _hmt || []; var _hmt = _hmt || [];
(function () { (function () {

View File

@ -1,4 +1,4 @@
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
@ -11,16 +11,20 @@
name="viewport" name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/> />
<%= meta %> <%- meta %>
<meta http-equiv="Cache-Control" content="no-cache" /> <meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" /> <meta http-equiv="Expires" content="0" />
<% if (headHtml) { %> <%= headHtml %> <% } %> <% if (enableVConsole) { %> <% if (headHtml) { %>
<%- headHtml %>
<% } %>
<% if (enableVConsole) { %>
<script src="https://unpkg.com/vconsole/dist/vconsole.min.js"></script> <script src="https://unpkg.com/vconsole/dist/vconsole.min.js"></script>
<script> <script>
var vConsole = new window.VConsole(); var vConsole = new window.VConsole();
</script> </script>
<% } %> <% if (baiduAnalytics) { %> <% } %>
<% if (baiduAnalytics) { %>
<script> <script>
// avoid to load analytics in iframe // avoid to load analytics in iframe
if (window.top === window) { if (window.top === window) {

View File

@ -1,11 +1,11 @@
<template> <template>
<demo-nav /> <demo-nav />
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<demo-section> <keep-alive>
<keep-alive> <demo-section>
<component :is="Component" /> <component :is="Component" />
</keep-alive> </demo-section>
</demo-section> </keep-alive>
</router-view> </router-view>
</template> </template>
@ -24,24 +24,15 @@ export default {
watch( watch(
theme, theme,
(newVal, oldVal) => { (newVal, oldVal) => {
document.documentElement.classList.remove(`van-doc-theme-${oldVal}`); document.body.classList.remove(`van-doc-theme-${oldVal}`);
document.documentElement.classList.add(`van-doc-theme-${newVal}`); document.body.classList.add(`van-doc-theme-${newVal}`);
const { darkModeClass, lightModeClass } = config.site; const { darkModeClass } = config.site;
if (darkModeClass) { if (darkModeClass) {
document.documentElement.classList.toggle( document.body.classList.toggle(darkModeClass, newVal === 'dark');
darkModeClass,
newVal === 'dark',
);
}
if (lightModeClass) {
document.documentElement.classList.toggle(
lightModeClass,
newVal === 'light',
);
} }
}, },
{ immediate: true }, { immediate: true }
); );
}, },
}; };
@ -52,7 +43,6 @@ export default {
body { body {
min-width: 100vw; min-width: 100vw;
background-color: inherit;
} }
.van-doc-theme-light { .van-doc-theme-light {

View File

@ -1,8 +1,6 @@
<template> <template>
<div class="van-doc-demo-block"> <div class="van-doc-demo-block">
<h2 v-if="title" class="van-doc-demo-block__title" :id="slugifyTitle"> <h2 v-if="title" class="van-doc-demo-block__title">{{ title }}</h2>
{{ title }}
</h2>
<div v-if="card" class="van-doc-demo-block__card"> <div v-if="card" class="van-doc-demo-block__card">
<slot /> <slot />
</div> </div>
@ -18,39 +16,6 @@ export default {
card: Boolean, card: Boolean,
title: String, title: String,
}, },
data() {
return {
slugify: null,
};
},
computed: {
slugifyTitle() {
return this.slugify ? this.slugify(this.title) : '';
},
},
watch: {
slugifyTitle(newVal) {
if (newVal) {
this.$nextTick(() => {
let hash = '';
if (top) hash = top.location.hash.split('#').pop();
else hash = location.hash.split('#').pop();
const target = document.getElementById(newVal);
if (target && newVal === hash) {
target.scrollIntoView(true);
}
});
}
},
},
async mounted() {
const { slugify } = await import('transliteration');
this.slugify = slugify;
},
}; };
</script> </script>

View File

@ -93,7 +93,6 @@ export default {
margin: 0 0 40px; margin: 0 0 40px;
color: var(--van-doc-text-color-4); color: var(--van-doc-text-color-4);
font-size: 14px; font-size: 14px;
line-height: 1.6;
} }
} }
</style> </style>

View File

@ -27,27 +27,23 @@ program
.description('Run unit tests through jest') .description('Run unit tests through jest')
.option( .option(
'--watch', '--watch',
'Watch files for changes and rerun tests related to changed files', 'Watch files for changes and rerun tests related to changed files'
) )
.option( .option(
'--clearCache', '--clearCache',
'Clears the configured Jest cache directory and then exits', 'Clears the configured Jest cache directory and then exits'
) )
.option( .option(
'--changedSince <changedSince>', '--changedSince <changedSince>',
'Runs tests related to the changes since the provided branch or commit hash', 'Runs tests related to the changes since the provided branch or commit hash'
) )
.option( .option(
'--logHeapUsage', '--logHeapUsage',
'Logs the heap usage after every test. Useful to debug memory leaks', 'Logs the heap usage after every test. Useful to debug memory leaks'
) )
.option( .option(
'--runInBand', '--runInBand',
'Run all tests serially in the current process, rather than creating a worker pool of child processes that run tests', 'Run all tests serially in the current process, rather than creating a worker pool of child processes that run tests'
)
.option(
'--updateSnapshot',
'Re-record every snapshot that fails during this test run',
) )
.option('--debug', 'Print debugging info about your Jest config') .option('--debug', 'Print debugging info about your Jest config')
.action(async (options) => { .action(async (options) => {

View File

@ -1,6 +1,6 @@
import fse from 'fs-extra'; import fse from 'fs-extra';
import { execa } from 'execa'; import execa from 'execa';
import { join, relative } from 'node:path'; import { join, relative } from 'path';
import { clean } from './clean.js'; import { clean } from './clean.js';
import { CSS_LANG } from '../common/css.js'; import { CSS_LANG } from '../common/css.js';
import { createSpinner, consola } from '../common/logger.js'; import { createSpinner, consola } from '../common/logger.js';
@ -66,7 +66,7 @@ async function preCompileDir(dir: string) {
return compileSfc(filePath); return compileSfc(filePath);
} }
return Promise.resolve(); return Promise.resolve();
}), })
); );
} }
@ -78,7 +78,7 @@ async function compileDir(dir: string, format: Format) {
return isDir(filePath) return isDir(filePath)
? compileDir(filePath, format) ? compileDir(filePath, format)
: compileFile(filePath, format); : compileFile(filePath, format);
}), })
); );
} }
@ -104,10 +104,7 @@ async function buildTypeDeclarations() {
const tsConfig = join(process.cwd(), 'tsconfig.declaration.json'); const tsConfig = join(process.cwd(), 'tsconfig.declaration.json');
if (existsSync(tsConfig)) { if (existsSync(tsConfig)) {
await execa('tsc', ['-p', tsConfig], { await execa('tsc', ['-p', tsConfig]);
stdout: 'inherit',
stderr: 'inherit',
});
} }
} }

View File

@ -1,8 +1,8 @@
import { join, dirname } from 'node:path'; import { join, dirname } from 'path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'url';
import { ROOT } from '../common/constant.js'; import { ROOT } from '../common/constant.js';
import { createSpinner, slimPath } from '../common/logger.js'; import { createSpinner, slimPath } from '../common/logger.js';
import { createWriteStream, readFileSync } from 'node:fs'; import { createWriteStream, readFileSync } from 'fs';
import conventionalChangelog from 'conventional-changelog'; import conventionalChangelog from 'conventional-changelog';
const DIST_FILE = join(ROOT, './changelog.generated.md'); const DIST_FILE = join(ROOT, './changelog.generated.md');
@ -64,7 +64,7 @@ export async function changelog(): Promise<void> {
headerPartial, headerPartial,
commitPartial, commitPartial,
transform, transform,
}, }
) )
.pipe(createWriteStream(DIST_FILE)) .pipe(createWriteStream(DIST_FILE))
.on('close', () => { .on('close', () => {

View File

@ -1,4 +1,4 @@
import { readFileSync } from 'node:fs'; import { readFileSync } from 'fs';
import { consola } from '../common/logger.js'; import { consola } from '../common/logger.js';
const commitRE = const commitRE =

View File

@ -24,7 +24,6 @@ export function test(command: Config.Argv) {
clearCache: command.clearCache, clearCache: command.clearCache,
changedSince: command.changedSince, changedSince: command.changedSince,
logHeapUsage: command.logHeapUsage, logHeapUsage: command.logHeapUsage,
updateSnapshot: command.updateSnapshot,
// make jest tests faster // make jest tests faster
// see: https://ivantanev.com/make-jest-faster/ // see: https://ivantanev.com/make-jest-faster/
maxWorkers: '50%', maxWorkers: '50%',

View File

@ -1,4 +1,4 @@
import { execa } from 'execa'; import execa from 'execa';
import { consola, createSpinner } from '../common/logger.js'; import { consola, createSpinner } from '../common/logger.js';
import { SCRIPT_EXTS } from '../common/constant.js'; import { SCRIPT_EXTS } from '../common/constant.js';
@ -11,14 +11,14 @@ type RunCommandMessages = {
function runCommand( function runCommand(
cmd: string, cmd: string,
options: string[], options: string[],
messages: RunCommandMessages, messages: RunCommandMessages
) { ) {
const spinner = createSpinner(messages.start).start(); const spinner = createSpinner(messages.start).start();
return new Promise((resolve) => { return new Promise((resolve) => {
execa(cmd, options, { execa(cmd, options, {
preferLocal: true, preferLocal: true,
env: { FORCE_COLOR: 'true' }, env: { FORCE_COLOR: true },
}) })
.then(() => { .then(() => {
spinner.success({ text: messages.succeed }); spinner.success({ text: messages.succeed });
@ -40,7 +40,7 @@ function eslint() {
start: 'Running eslint...', start: 'Running eslint...',
succeed: 'ESLint Passed.', succeed: 'ESLint Passed.',
failed: 'ESLint failed!', failed: 'ESLint failed!',
}, }
); );
} }

View File

@ -1,7 +1,7 @@
/* eslint-disable no-template-curly-in-string */ /* eslint-disable no-template-curly-in-string */
import releaseIt from 'release-it'; import releaseIt from 'release-it';
import { join, dirname } from 'node:path'; import { join, dirname } from 'path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
const PLUGIN_PATH = join(__dirname, '../compiler/vant-cli-release-plugin.js'); const PLUGIN_PATH = join(__dirname, '../compiler/vant-cli-release-plugin.js');

View File

@ -1,6 +1,6 @@
import { existsSync, readFileSync } from 'node:fs'; import { existsSync, readFileSync } from 'fs';
import { fileURLToPath, pathToFileURL } from 'node:url'; import { fileURLToPath, pathToFileURL } from 'url';
import { join, dirname, isAbsolute } from 'node:path'; import { join, dirname, isAbsolute } from 'path';
function findRootDir(dir: string): string { function findRootDir(dir: string): string {
if (existsSync(join(dir, 'vant.config.mjs'))) { if (existsSync(join(dir, 'vant.config.mjs'))) {

View File

@ -1,5 +1,5 @@
import { existsSync } from 'node:fs'; import { existsSync } from 'fs';
import { join, isAbsolute } from 'node:path'; import { join, isAbsolute } from 'path';
import { getVantConfig } from '../common/index.js'; import { getVantConfig } from '../common/index.js';
import { STYLE_DIR, SRC_DIR } from './constant.js'; import { STYLE_DIR, SRC_DIR } from './constant.js';
@ -39,6 +39,6 @@ const IMPORT_STYLE_RE = /import\s+?(?:(?:".*?")|(?:'.*?'))[\s]*?(?:;|$|)/g;
// "import 'a.less';" => "import 'a.css';" // "import 'a.less';" => "import 'a.css';"
export function replaceCSSImportExt(code: string) { export function replaceCSSImportExt(code: string) {
return code.replace(IMPORT_STYLE_RE, (str) => return code.replace(IMPORT_STYLE_RE, (str) =>
str.replace(`.${CSS_LANG}`, '.css'), str.replace(`.${CSS_LANG}`, '.css')
); );
} }

View File

@ -1,7 +1,7 @@
import fse from 'fs-extra'; import fse from 'fs-extra';
import { sep, join } from 'node:path'; import { sep, join } from 'path';
import { SRC_DIR, getVantConfig } from './constant.js'; import { SRC_DIR, getVantConfig } from './constant.js';
import { InlineConfig, loadConfigFromFile, mergeConfig } from 'vite'; import type { InlineConfig } from 'vite';
const { lstatSync, existsSync, readdirSync, readFileSync, outputFileSync } = const { lstatSync, existsSync, readdirSync, readFileSync, outputFileSync } =
fse; fse;
@ -42,7 +42,7 @@ export function getComponents() {
} }
return false; return false;
}), })
); );
} }
@ -65,7 +65,7 @@ export function camelize(str: string): string {
export function pascalize(str: string): string { export function pascalize(str: string): string {
return camelize(str).replace( return camelize(str).replace(
pascalizeRE, pascalizeRE,
(_, c1, c2) => c1.toUpperCase() + c2, (_, c1, c2) => c1.toUpperCase() + c2
); );
} }
@ -114,33 +114,13 @@ export function smartOutputFile(filePath: string, content: string) {
outputFileSync(filePath, content); outputFileSync(filePath, content);
} }
export async function mergeCustomViteConfig( export function mergeCustomViteConfig(config: InlineConfig) {
config: InlineConfig,
mode: 'production' | 'development',
): Promise<InlineConfig> {
const vantConfig = getVantConfig(); const vantConfig = getVantConfig();
const configureVite = vantConfig.build?.configureVite; const configureVite = vantConfig.build?.configureVite;
const userConfig = await loadConfigFromFile(
{
mode,
command: mode === 'development' ? 'serve' : 'build',
},
undefined,
process.cwd(),
);
if (configureVite) { if (configureVite) {
const ret = configureVite(config); return configureVite(config);
if (ret) {
config = ret;
}
} }
if (userConfig) {
return mergeConfig(config, userConfig.config);
}
return config; return config;
} }

View File

@ -1,6 +1,6 @@
import { createSpinner } from 'nanospinner'; import { createSpinner } from 'nanospinner';
import color from 'picocolors'; import color from 'picocolors';
import { consola } from 'consola'; import consola from 'consola';
import { ROOT } from '../common/constant.js'; import { ROOT } from '../common/constant.js';
export function slimPath(path: string) { export function slimPath(path: string) {

View File

@ -1,4 +1,4 @@
import { execa } from 'execa'; import execa from 'execa';
import { consola } from './logger.js'; import { consola } from './logger.js';
import { execSync } from 'child_process'; import { execSync } from 'child_process';
import { getVantConfig } from './constant.js'; import { getVantConfig } from './constant.js';

View File

@ -34,13 +34,8 @@ export async function compileBundles() {
getVantConfig().build?.bundleOptions || DEFAULT_OPTIONS; getVantConfig().build?.bundleOptions || DEFAULT_OPTIONS;
await Promise.all( await Promise.all(
bundleOptions.map(async (config) => bundleOptions.map((config) =>
build( build(mergeCustomViteConfig(getViteConfigForPackage(config)))
await mergeCustomViteConfig( )
getViteConfigForPackage(config),
'production',
),
),
),
); );
} }

View File

@ -1,6 +1,6 @@
import less from 'less'; import less from 'less';
import { join } from 'node:path'; import { join } from 'path';
import { readFileSync } from 'node:fs'; import { readFileSync } from 'fs';
import { CWD } from '../common/constant.js'; import { CWD } from '../common/constant.js';
export async function compileLess(filePath: string) { export async function compileLess(filePath: string) {

View File

@ -1,4 +1,4 @@
import { createRequire } from 'node:module'; import { createRequire } from 'module';
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);

View File

@ -1,7 +1,7 @@
import fse from 'fs-extra'; import fse from 'fs-extra';
import babel from '@babel/core'; import babel from '@babel/core';
import esbuild, { type Format } from 'esbuild'; import esbuild, { type Format } from 'esbuild';
import { sep } from 'node:path'; import { sep } from 'path';
import { isJsx, replaceExt, getVantConfig } from '../common/index.js'; import { isJsx, replaceExt, getVantConfig } from '../common/index.js';
import { replaceCSSImportExt } from '../common/css.js'; import { replaceCSSImportExt } from '../common/css.js';
import { replaceScriptImportExt } from './get-deps.js'; import { replaceScriptImportExt } from './get-deps.js';
@ -10,7 +10,7 @@ const { readFileSync, removeSync, outputFileSync } = fse;
export async function compileScript( export async function compileScript(
filePath: string, filePath: string,
format: Format, format: Format
): Promise<void> { ): Promise<void> {
if (filePath.includes('.d.ts')) { if (filePath.includes('.d.ts')) {
return; return;

View File

@ -1,5 +1,5 @@
import fse from 'fs-extra'; import fse from 'fs-extra';
import path from 'node:path'; import path from 'path';
import hash from 'hash-sum'; import hash from 'hash-sum';
import { import {
parse, parse,
@ -127,7 +127,7 @@ export async function compileSfc(filePath: string): Promise<any> {
} }
outputFile(scriptFilePath, script).then(resolve); outputFile(scriptFilePath, script).then(resolve);
}), })
); );
} }
@ -150,7 +150,7 @@ export async function compileSfc(filePath: string): Promise<any> {
// } // }
return outputFile(cssFilePath, styleSource); return outputFile(cssFilePath, styleSource);
}), })
); );
return Promise.all(tasks); return Promise.all(tasks);

View File

@ -1,5 +1,5 @@
import color from 'picocolors'; import color from 'picocolors';
import { createRequire } from 'node:module'; import { createRequire } from 'module';
import { createServer, build } from 'vite'; import { createServer, build } from 'vite';
import { import {
getViteConfigForSiteDev, getViteConfigForSiteDev,
@ -29,18 +29,12 @@ export function genSiteEntry(): Promise<void> {
export async function compileSite(production = false) { export async function compileSite(production = false) {
await genSiteEntry(); await genSiteEntry();
if (production) { if (production) {
const config = await mergeCustomViteConfig( const config = mergeCustomViteConfig(getViteConfigForSiteProd());
getViteConfigForSiteProd(),
'production',
);
await build(config); await build(config);
} else { } else {
const config = await mergeCustomViteConfig( const config = mergeCustomViteConfig(getViteConfigForSiteDev());
getViteConfigForSiteDev(),
'development',
);
const server = await createServer(config); const server = await createServer(config);
await server.listen(config.server?.port); await server.listen();
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const { version } = require('vite/package.json'); const { version } = require('vite/package.json');

View File

@ -1,4 +1,4 @@
import { parse } from 'node:path'; import { parse } from 'path';
import fse from 'fs-extra'; import fse from 'fs-extra';
import { getVantConfig, replaceExt } from '../common/index.js'; import { getVantConfig, replaceExt } from '../common/index.js';
import { compileCss } from './compile-css.js'; import { compileCss } from './compile-css.js';

View File

@ -3,8 +3,8 @@
*/ */
import fse from 'fs-extra'; import fse from 'fs-extra';
import { createRequire } from 'node:module'; import { createRequire } from 'module';
import { sep, join, relative } from 'node:path'; import { sep, join, relative } from 'path';
import { getComponents, replaceExt } from '../common/index.js'; import { getComponents, replaceExt } from '../common/index.js';
import { CSS_LANG, getCssBaseFile } from '../common/css.js'; import { CSS_LANG, getCssBaseFile } from '../common/css.js';
import { checkStyleExists } from './gen-style-deps-map.js'; import { checkStyleExists } from './gen-style-deps-map.js';
@ -81,7 +81,7 @@ function genEntry(params: {
} }
export function genComponentStyle( export function genComponentStyle(
options: { cache: boolean } = { cache: true }, options: { cache: boolean } = { cache: true }
) { ) {
if (!options.cache) { if (!options.cache) {
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);

View File

@ -1,4 +1,4 @@
import { join } from 'node:path'; import { join } from 'path';
import { import {
pascalize, pascalize,
getComponents, getComponents,
@ -20,7 +20,7 @@ function getPathByName(name: string, pathResolver?: PathResolver) {
function genImports( function genImports(
names: string[], names: string[],
pathResolver?: PathResolver, pathResolver?: PathResolver,
namedExport?: boolean, namedExport?: boolean
): string { ): string {
return names return names
.map((name) => { .map((name) => {
@ -36,7 +36,7 @@ function genImports(
function genExports( function genExports(
names: string[], names: string[],
pathResolver?: PathResolver, pathResolver?: PathResolver,
namedExport?: boolean, namedExport?: boolean
): string { ): string {
if (namedExport) { if (namedExport) {
const exports = names const exports = names

View File

@ -1,6 +1,6 @@
import { join } from 'node:path'; import { join } from 'path';
import { existsSync } from 'node:fs'; import { existsSync } from 'fs';
import { createRequire } from 'node:module'; import { createRequire } from 'module';
import { smartOutputFile, normalizePath } from '../common/index.js'; import { smartOutputFile, normalizePath } from '../common/index.js';
import { CSS_LANG, getCssBaseFile } from '../common/css.js'; import { CSS_LANG, getCssBaseFile } from '../common/css.js';
import { SRC_DIR, STYLE_DEPS_JSON_FILE } from '../common/constant.js'; import { SRC_DIR, STYLE_DEPS_JSON_FILE } from '../common/constant.js';

View File

@ -1,7 +1,12 @@
import glob from 'fast-glob'; import glob from 'fast-glob';
import { join, parse } from 'node:path'; import { join, parse } from 'path';
import { existsSync, readFileSync, readdirSync } from 'node:fs'; import { existsSync, readFileSync, readdirSync } from 'fs';
import { pascalize, getVantConfig, normalizePath } from '../common/index.js'; import {
isDev,
pascalize,
getVantConfig,
normalizePath,
} from '../common/index.js';
import { import {
SRC_DIR, SRC_DIR,
DOCS_DIR, DOCS_DIR,
@ -75,7 +80,10 @@ function genImportDocuments(items: DocumentItem[]) {
return items return items
.map((item) => { .map((item) => {
const path = normalizePath(item.path); const path = normalizePath(item.path);
return `const ${item.name} = () => import('${path}');`; if (isDev()) {
return `const ${item.name} = () => import('${path}');`;
}
return `import ${item.name} from '${path}';`;
}) })
.join('\n'); .join('\n');
} }

View File

@ -1,5 +1,5 @@
import { join } from 'node:path'; import { join } from 'path';
import { existsSync, readdirSync } from 'node:fs'; import { existsSync, readdirSync } from 'fs';
import { SRC_DIR } from '../common/constant.js'; import { SRC_DIR } from '../common/constant.js';
import { import {
pascalize, pascalize,
@ -38,7 +38,7 @@ function genConfig(demos: DemoItem[]) {
function demoFilter(nav: any[]) { function demoFilter(nav: any[]) {
return nav.filter((group) => { return nav.filter((group) => {
group.items = group.items.filter((item: any) => group.items = group.items.filter((item: any) =>
demoNames.includes(item.path), demoNames.includes(item.path)
); );
return group.items.length; return group.items.length;
}); });

View File

@ -1,6 +1,6 @@
import { relative, sep, join } from 'node:path'; import { relative, sep, join } from 'path';
import { CSS_LANG } from '../common/css.js'; import { CSS_LANG } from '../common/css.js';
import { existsSync } from 'node:fs'; import { existsSync } from 'fs';
import { getDeps, clearDepsCache, fillExt } from './get-deps.js'; import { getDeps, clearDepsCache, fillExt } from './get-deps.js';
import { getComponents, smartOutputFile } from '../common/index.js'; import { getComponents, smartOutputFile } from '../common/index.js';
import { SRC_DIR, STYLE_DEPS_JSON_FILE } from '../common/constant.js'; import { SRC_DIR, STYLE_DEPS_JSON_FILE } from '../common/constant.js';
@ -106,13 +106,13 @@ export async function genStyleDepsMap() {
Object.keys(map).forEach((key) => { Object.keys(map).forEach((key) => {
map[key] = map[key].sort( map[key] = map[key].sort(
(a, b) => sequence.indexOf(a) - sequence.indexOf(b), (a, b) => sequence.indexOf(a) - sequence.indexOf(b)
); );
}); });
smartOutputFile( smartOutputFile(
STYLE_DEPS_JSON_FILE, STYLE_DEPS_JSON_FILE,
JSON.stringify({ map, sequence }, null, 2), JSON.stringify({ map, sequence }, null, 2)
); );
resolve(); resolve();

View File

@ -1,6 +1,6 @@
import { join } from 'node:path'; import { join } from 'path';
import { SCRIPT_EXTS, STYLE_EXTS } from '../common/constant.js'; import { SCRIPT_EXTS, STYLE_EXTS } from '../common/constant.js';
import { readFileSync, existsSync } from 'node:fs'; import { readFileSync, existsSync } from 'fs';
let depsMap: Record<string, string[]> = {}; let depsMap: Record<string, string[]> = {};
let existsCache: Record<string, boolean> = {}; let existsCache: Record<string, boolean> = {};
@ -105,7 +105,7 @@ export function getDeps(filePath: string) {
export function replaceScriptImportExt( export function replaceScriptImportExt(
code: string, code: string,
filePath: string, filePath: string,
ext: string, ext: string
) { ) {
const imports = [...matchImports(code), ...matchExportFroms(code)]; const imports = [...matchImports(code), ...matchExportFroms(code)];
@ -127,11 +127,6 @@ export function replaceScriptImportExt(
return; return;
} }
const isExistExt = line.includes(ext);
if (isExistExt) {
return;
}
const pathInfo = getPathByImport(line, filePath); const pathInfo = getPathByImport(line, filePath);
if (pathInfo) { if (pathInfo) {
@ -140,7 +135,7 @@ export function replaceScriptImportExt(
if (pathInfo.isIndex) { if (pathInfo.isIndex) {
const newLine = line.replace( const newLine = line.replace(
relativePath, relativePath,
`${relativePath}/index${ext}`, `${relativePath}/index${ext}`
); );
updateImport(index, newLine); updateImport(index, newLine);

View File

@ -1,6 +1,11 @@
/* eslint-disable no-continue */ /* eslint-disable no-continue */
import { Articles } from './parser.js'; import { Articles } from './parser.js';
import { formatType, removeVersion, toKebabCase } from './utils.js'; import {
formatOptions,
formatType,
removeVersion,
toKebabCase,
} from './utils.js';
import { VueEventArgument, VueTag } from './type.js'; import { VueEventArgument, VueTag } from './type.js';
function formatComponentName(name: string, tagPrefix: string) { function formatComponentName(name: string, tagPrefix: string) {
@ -29,15 +34,9 @@ function formatArguments(input: string): VueEventArgument[] {
} else if ([':', ',', '_', ' '].includes(input[0])) { } else if ([':', ',', '_', ' '].includes(input[0])) {
input = input.substring(1); input = input.substring(1);
} else { } else {
const matched = input.match(/( |'|\||\w)+/); const val = input.match(/( |'|\||\w)+/)![0] || '';
input = input.substring(val.length);
if (matched?.length && matched[0]) { items.push(val);
const val = matched[0];
input = input.substring(val.length);
items.push(val);
} else {
input = '';
}
} }
} }
@ -67,6 +66,9 @@ function findTag(vueTags: VueTag[], name: string) {
const newTag: VueTag = { const newTag: VueTag = {
name, name,
slots: [],
events: [],
attributes: [],
}; };
vueTags.push(newTag); vueTags.push(newTag);
@ -77,7 +79,7 @@ function findTag(vueTags: VueTag[], name: string) {
export function formatter( export function formatter(
vueTags: VueTag[], vueTags: VueTag[],
articles: Articles, articles: Articles,
tagPrefix = '', tagPrefix = ''
) { ) {
if (!articles.length) { if (!articles.length) {
return; return;
@ -105,16 +107,12 @@ export function formatter(
const tag = findTag(vueTags, name); const tag = findTag(vueTags, name);
table.body.forEach((line) => { table.body.forEach((line) => {
const [name, desc, type, defaultVal] = line; const [name, desc, type, defaultVal, options] = line;
tag.attributes!.push({
if (!tag.attributes) {
tag.attributes = [];
}
tag.attributes.push({
name: removeVersion(name), name: removeVersion(name),
default: defaultVal, default: defaultVal,
description: desc, description: desc,
options: formatOptions(options),
value: { value: {
type: formatType(type), type: formatType(type),
kind: 'expression', kind: 'expression',
@ -130,12 +128,7 @@ export function formatter(
table.body.forEach((line) => { table.body.forEach((line) => {
const [name, desc, args] = line; const [name, desc, args] = line;
tag.events!.push({
if (!tag.events) {
tag.events = [];
}
tag.events.push({
name: removeVersion(name), name: removeVersion(name),
description: desc, description: desc,
arguments: formatArguments(args), arguments: formatArguments(args),
@ -150,12 +143,7 @@ export function formatter(
table.body.forEach((line) => { table.body.forEach((line) => {
const [name, desc] = line; const [name, desc] = line;
tag.slots!.push({
if (!tag.slots) {
tag.slots = [];
}
tag.slots.push({
name: removeVersion(name), name: removeVersion(name),
description: desc, description: desc,
}); });

View File

@ -1,5 +1,5 @@
import glob from 'fast-glob'; import glob from 'fast-glob';
import { join } from 'node:path'; import { join } from 'path';
import fse from 'fs-extra'; import fse from 'fs-extra';
import { mdParser } from './parser.js'; import { mdParser } from './parser.js';
import { formatter } from './formatter.js'; import { formatter } from './formatter.js';
@ -36,7 +36,7 @@ export async function parseAndWrite(options: Options) {
const webTypes = genWebTypes(vueTags, options); const webTypes = genWebTypes(vueTags, options);
fse.outputFileSync( fse.outputFileSync(
join(options.outputDir, 'web-types.json'), join(options.outputDir, 'web-types.json'),
JSON.stringify(webTypes), JSON.stringify(webTypes, null, 2)
); );
} }

View File

@ -1,4 +1,4 @@
import { PathLike } from 'node:fs'; import { PathLike } from 'fs';
export type VueSlot = { export type VueSlot = {
name: string; name: string;
@ -20,6 +20,7 @@ export type VueAttribute = {
name: string; name: string;
default: string; default: string;
description: string; description: string;
options: string[];
value: { value: {
kind: 'expression'; kind: 'expression';
type: string; type: string;

View File

@ -2,7 +2,7 @@
export function toKebabCase(input: string): string { export function toKebabCase(input: string): string {
return input.replace( return input.replace(
/[A-Z]/g, /[A-Z]/g,
(val, index) => (index === 0 ? '' : '-') + val.toLowerCase(), (val, index) => (index === 0 ? '' : '-') + val.toLowerCase()
); );
} }
@ -20,3 +20,9 @@ export function formatType(type: string) {
export function normalizePath(path: string): string { export function normalizePath(path: string): string {
return path.replace(/\\/g, '/'); return path.replace(/\\/g, '/');
} }
// `default` `primary` -> ['default', 'primary']
export function formatOptions(options?: string) {
if (!options) return [];
return options.replace(/`/g, '').split(' ');
}

View File

@ -12,8 +12,8 @@ export function genWebTypes(tags: VueTag[], options: Options) {
html: { html: {
tags, tags,
attributes: [], attributes: [],
'types-syntax': 'typescript',
}, },
}, },
'js-types-syntax': 'typescript',
}; };
} }

View File

@ -1,4 +1,4 @@
import { join } from 'node:path'; import { join } from 'path';
import { setBuildTarget } from '../common/index.js'; import { setBuildTarget } from '../common/index.js';
import { CWD, ES_DIR, getVantConfig, LIB_DIR } from '../common/constant.js'; import { CWD, ES_DIR, getVantConfig, LIB_DIR } from '../common/constant.js';
import type { InlineConfig } from 'vite'; import type { InlineConfig } from 'vite';
@ -28,8 +28,6 @@ export function getViteConfigForPackage({
: undefined, : undefined,
build: { build: {
emptyOutDir: false,
lib: { lib: {
name, name,
entry, entry,

View File

@ -1,12 +1,12 @@
import { join } from 'node:path'; import { join } from 'path';
import { createRequire } from 'node:module'; import { createRequire } from 'module';
import hljs from 'highlight.js'; import hljs from 'highlight.js';
import vitePluginMd from 'vite-plugin-md'; import vitePluginMd from 'vite-plugin-md';
import vitePluginVue from '@vitejs/plugin-vue'; import vitePluginVue from '@vitejs/plugin-vue';
import vitePluginJsx from '@vitejs/plugin-vue-jsx'; import vitePluginJsx from '@vitejs/plugin-vue-jsx';
import { setBuildTarget, getVantConfig, isDev } from '../common/index.js'; import { setBuildTarget, getVantConfig, isDev } from '../common/index.js';
import { SITE_DIST_DIR, SITE_SRC_DIR } from '../common/constant.js'; import { SITE_DIST_DIR, SITE_SRC_DIR } from '../common/constant.js';
import lodash from 'lodash'; import { injectHtml } from 'vite-plugin-html';
import type { InlineConfig, PluginOption } from 'vite'; import type { InlineConfig, PluginOption } from 'vite';
import type MarkdownIt from 'markdown-it'; import type MarkdownIt from 'markdown-it';
import { genSiteMobileShared } from '../compiler/gen-site-mobile-shared.js'; import { genSiteMobileShared } from '../compiler/gen-site-mobile-shared.js';
@ -131,18 +131,6 @@ function vitePluginGenVantBaseCode(): PluginOption {
}; };
} }
function vitePluginHTML(data: object): PluginOption {
return {
name: 'vite-plugin-html',
transformIndexHtml: {
enforce: 'pre',
transform(html) {
return lodash.template(html)(data);
},
},
};
}
export function getViteConfigForSiteDev(): InlineConfig { export function getViteConfigForSiteDev(): InlineConfig {
setBuildTarget('site'); setBuildTarget('site');
@ -156,11 +144,6 @@ export function getViteConfigForSiteDev(): InlineConfig {
return { return {
root: SITE_SRC_DIR, root: SITE_SRC_DIR,
optimizeDeps: {
// https://github.com/youzan/vant/issues/10930
include: ['vue', 'vue-router'],
},
plugins: [ plugins: [
vitePluginGenVantBaseCode(), vitePluginGenVantBaseCode(),
vitePluginVue({ vitePluginVue({
@ -189,16 +172,18 @@ export function getViteConfigForSiteDev(): InlineConfig {
}, },
}), }),
vitePluginJsx(), vitePluginJsx(),
vitePluginHTML({ injectHtml({
...siteConfig, data: {
title, ...siteConfig,
// `description` is used by the HTML ejs template, title,
// so it needs to be written explicitly here to avoid error: description is not defined // `description` is used by the HTML ejs template,
description: siteConfig.description, // so it needs to be written explicitly here to avoid error: description is not defined
headHtml, description: siteConfig.description,
baiduAnalytics, headHtml,
enableVConsole, baiduAnalytics,
meta: getHTMLMeta(vantConfig), enableVConsole,
meta: getHTMLMeta(vantConfig),
},
}), }),
], ],

View File

@ -1,6 +1,6 @@
// @ts-ignore // @ts-ignore
import fs from 'node:fs'; import fs from 'fs';
import { URL, fileURLToPath } from 'node:url'; import { URL, fileURLToPath } from 'url';
const packagePath = fileURLToPath(new URL('../package.json', import.meta.url)); const packagePath = fileURLToPath(new URL('../package.json', import.meta.url));
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8')); const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));

View File

@ -1,4 +1,5 @@
// some modules with missing type definitions // some modules with missing type definitions
declare module 'execa';
declare module 'hash-sum'; declare module 'hash-sum';
declare module '@babel/core'; declare module '@babel/core';
declare module 'release-it'; declare module 'release-it';

View File

@ -32,3 +32,4 @@
{{~/if}} {{~/if}}
/{{~@root.commit}}/{{hash}}) /{{~@root.commit}}/{{hash}})
{{~/if}} {{~/if}}

View File

@ -5,6 +5,5 @@
"outDir": "./lib", "outDir": "./lib",
"declaration": true "declaration": true
}, },
"include": ["src/**/*"], "include": ["src/**/*"]
"exclude": ["**/node_modules", "**/.*/"]
} }

View File

@ -36,18 +36,17 @@
"author": "chenjiahan", "author": "chenjiahan",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@vue/runtime-core": "^3.3.4", "@vue/runtime-core": "^3.2.27",
"vant": "workspace:*", "vant": "workspace:*",
"vue": "^3.3.4", "vue": "^3.2.27",
"esbuild": "^0.18.11", "esbuild": "^0.14.29",
"release-it": "^15.1.1", "release-it": "^15.1.1",
"rimraf": "^5.0.0", "typescript": "^4.7.4"
"typescript": "^5.0.4"
}, },
"release-it": { "release-it": {
"git": { "git": {
"tag": false, "tag": false,
"commitMessage": "release: @vant/compat v${version}" "commitMessage": "release: @vant/compat ${version}"
} }
} }
} }

View File

@ -4,6 +4,5 @@
"outDir": "./dist", "outDir": "./dist",
"declaration": true "declaration": true
}, },
"include": ["src/**/*"], "include": ["src/**/*"]
"exclude": ["**/node_modules", "**/.*/"]
} }

View File

@ -1,7 +1,7 @@
module.exports = { module.exports = {
extends: [ extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended', 'plugin:vue/vue3-recommended',
'airbnb-base',
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
'prettier', 'prettier',
], ],
@ -23,7 +23,28 @@ module.exports = {
}, },
rules: { rules: {
'no-new': 'off',
'no-shadow': 'off',
'no-bitwise': 'off',
'func-names': 'off',
'no-console': 'off',
'no-plusplus': 'off',
'default-case': 'off',
'prefer-template': 'off',
'consistent-return': 'off',
'no-param-reassign': 'off',
'no-nested-ternary': 'off',
'no-underscore-dangle': 'off',
'no-unused-expressions': 'off',
'no-restricted-globals': 'off',
'class-methods-use-this': 'off',
'prefer-destructuring': ['error', { object: true, array: false }], 'prefer-destructuring': ['error', { object: true, array: false }],
// eslint-plugin-import
'import/order': 'off',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
// eslint-plugin-vue // eslint-plugin-vue
'vue/no-v-html': 'off', 'vue/no-v-html': 'off',
'vue/attributes-order': 'off', 'vue/attributes-order': 'off',

View File

@ -0,0 +1,4 @@
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
resolver: '<rootDir>/jest.resolver.js',
};

View File

@ -0,0 +1,13 @@
// https://github.com/facebook/jest/issues/9771#issuecomment-871585234
const resolver = require('enhanced-resolve').create.sync({
conditionNames: ['require', 'node', 'default'],
extensions: ['.js', '.json', '.node', '.ts', '.tsx'],
});
module.exports = function (request, options) {
// list global module that must be resolved by defaultResolver here
if (['fs', 'http', 'path'].includes(request)) {
return options.defaultResolver(request, options);
}
return resolver(options.basedir, request);
};

View File

@ -1,6 +1,6 @@
{ {
"name": "@vant/eslint-config", "name": "@vant/eslint-config",
"version": "4.0.0", "version": "3.5.0",
"description": "eslint config of vant", "description": "eslint config of vant",
"main": "index.js", "main": "index.js",
"publishConfig": { "publishConfig": {
@ -8,7 +8,8 @@
"registry": "https://registry.npmjs.org/" "registry": "https://registry.npmjs.org/"
}, },
"scripts": { "scripts": {
"update:deps": "pnpm update --latest --interactive" "update:deps": "pnpm update --latest --interactive",
"test": "jest"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -19,14 +20,17 @@
"author": "chenjiahan", "author": "chenjiahan",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "^5.60.1", "@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.60.1", "@typescript-eslint/parser": "^5.36.1",
"eslint-config-prettier": "^8.8.0", "eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-vue": "^9.15.1" "eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-vue": "^9.4.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.44.0", "enhanced-resolve": "^5.10.0",
"typescript": "^5.0.4" "eslint": "^8.23.0",
"typescript": "^4.8.2"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^7.32.0 || ^8.2.0" "eslint": "^7.32.0 || ^8.2.0"

View File

@ -0,0 +1,4 @@
{
"root": true,
"extends": ["../index"]
}

View File

@ -0,0 +1,41 @@
const { ESLint } = require('eslint');
const path = require('path');
const eslint = new ESLint();
async function lintProject(name) {
const projectPath = path.resolve(__dirname, name);
const filesToLint = path.resolve(projectPath, '**');
const rest = await eslint.lintFiles(filesToLint);
const ruleId = [];
rest.forEach((res) =>
res.messages.forEach((msg) => {
if (ruleId.indexOf(msg.ruleId) < 0) {
ruleId.push(msg.ruleId);
}
})
);
return ruleId;
}
test('a vue project should pass lint', async () => {
const rest = await lintProject('vue');
expect([
'no-const-assign',
'@typescript-eslint/no-unused-vars',
'vue/multi-word-component-names',
'no-undef',
]).toEqual(rest);
});
test('a vue-tsx project should pass lint', async () => {
const rest = await lintProject('vue-tsx');
expect([
'@typescript-eslint/no-unused-vars',
'vue/multi-word-component-names',
'vue/no-ref-as-operand',
'@typescript-eslint/no-empty-interface',
]).toEqual(rest);
});

View File

@ -0,0 +1,12 @@
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App',
setup() {
return () => (
<>
<h1>App</h1>
</>
);
},
});

View File

@ -0,0 +1,23 @@
import { defineComponent, ref } from 'vue';
import App from './app';
const h2 = 1;
export default defineComponent({
name: 'Index',
setup() {
const count = ref(0);
count++;
count + 1;
1 + count;
return () => (
<>
<h1>About</h1>
<App />
</>
);
},
});

Some files were not shown because too many files have changed in this diff Show More