first commit
This commit is contained in:
1
vant/packages/.pydio
Normal file
1
vant/packages/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
1c66f35f-f1e5-48f4-9816-87982334b9dd
|
||||
1
vant/packages/create-vant-cli-app/.pydio
Normal file
1
vant/packages/create-vant-cli-app/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
4a848747-b0de-4fe8-a636-8aecb24ee3de
|
||||
1
vant/packages/create-vant-cli-app/generators/.pydio
Normal file
1
vant/packages/create-vant-cli-app/generators/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
d6d89bb3-9916-4e8d-ac56-a3bd71552b71
|
||||
@@ -0,0 +1 @@
|
||||
4a93d437-eba6-40ec-b788-2528b7d4220a
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ['@vant/cli/preset'],
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
c6aef35f-69ff-4e94-a2c6-bcad4032480c
|
||||
@@ -0,0 +1,11 @@
|
||||
# 介绍
|
||||
|
||||
### 关于
|
||||
|
||||
这是一段组件库的介绍
|
||||
|
||||
### 特性
|
||||
|
||||
- 特性一
|
||||
- 特性二
|
||||
- 特性三
|
||||
@@ -0,0 +1,11 @@
|
||||
# 快速上手
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
# 通过 npm 安装
|
||||
npm i <%= name %> -S
|
||||
|
||||
# 通过 yarn 安装
|
||||
yarn add <%= name %>
|
||||
```
|
||||
@@ -0,0 +1,4 @@
|
||||
es
|
||||
lib
|
||||
dist
|
||||
node_modules
|
||||
@@ -0,0 +1,17 @@
|
||||
*.log*
|
||||
.cache
|
||||
.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
package-lock.json
|
||||
|
||||
# dist file
|
||||
es
|
||||
lib
|
||||
site
|
||||
|
||||
# test
|
||||
test/coverage
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "<%= name %>",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "lib/<%= name %>.js",
|
||||
"style": "lib/index.css",
|
||||
"files": [
|
||||
"lib",
|
||||
"es"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "vant-cli dev",
|
||||
"test": "vant-cli test",
|
||||
"lint": "vant-cli lint",
|
||||
"build": "vant-cli build",
|
||||
"release": "vant-cli release",
|
||||
"test:coverage": "open test/coverage/index.html",
|
||||
"build-site": "vant-cli build-site && gh-pages -d site"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged",
|
||||
"commit-msg": "vant-cli commit-lint"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx,js,jsx,vue}": [
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
],
|
||||
"*.{vue,css,less,scss}": [
|
||||
"stylelint --fix",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.6.11",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vant/cli": "^2.0.0",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"extends": [
|
||||
"@vant"
|
||||
]
|
||||
},
|
||||
"stylelint": {
|
||||
"extends": [
|
||||
"@vant/stylelint-config"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
},
|
||||
"browserslist": [
|
||||
"Android >= 4.0",
|
||||
"iOS >= 8"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
1f7b797d-f8bb-4eec-9206-309003f22b93
|
||||
@@ -0,0 +1 @@
|
||||
e3e24d50-1d42-4639-afaa-bc6d9312d493
|
||||
@@ -0,0 +1,43 @@
|
||||
# DemoButton 按钮
|
||||
|
||||
### 介绍
|
||||
|
||||
DemoButton 是一个示例按钮组件
|
||||
|
||||
### 引入
|
||||
|
||||
```js
|
||||
import Vue from 'vue';
|
||||
import { DemoButton } from '<%= name %>';
|
||||
|
||||
Vue.use(DemoButton);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础用法
|
||||
|
||||
```html
|
||||
<demo-button type="primary" />
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|------|------|------|------|
|
||||
| type | 按钮类型 | *string* | `primary` |
|
||||
| color `1.0.0` | 按钮颜色 | *string* | - |
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
|------|------|------|
|
||||
| click | 点击时触发 | event: Event |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
|------|------|
|
||||
| default | 默认插槽 |
|
||||
@@ -0,0 +1 @@
|
||||
22dc34dc-e3e8-43b5-99e2-ea9aab9bcc4d
|
||||
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block title="基础用法">
|
||||
<demo-button type="primary" style="margin-left: 15px;">按钮</demo-button>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="自定义颜色">
|
||||
<demo-button color="#03a9f4" style="margin-left: 15px;">按钮</demo-button>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<button class="demo-button">
|
||||
<slot />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'demo-button',
|
||||
|
||||
props: {
|
||||
color: String,
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary',
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="<%= cssLang %>">
|
||||
.demo-button {
|
||||
min-width: 120px;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 36px;
|
||||
background-color: #f44;
|
||||
border: none;
|
||||
border-radius: 30px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1 @@
|
||||
880a5847-13d7-4fb0-957c-9b1f9cb9c050
|
||||
@@ -0,0 +1 @@
|
||||
5792c86b-75c0-4d46-9475-ae7c5aa63be4
|
||||
@@ -0,0 +1,3 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`render demo button 1`] = `<button class="demo-button"></button>`;
|
||||
@@ -0,0 +1,7 @@
|
||||
import { mount } from '@vue/test-utils';
|
||||
import DemoButton from '..';
|
||||
|
||||
test('render demo button', () => {
|
||||
const wrapper = mount(DemoButton);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
module.exports = {
|
||||
name: '<%= name %>',
|
||||
build: {
|
||||
css: {
|
||||
preprocessor: '<%= preprocessor %>',
|
||||
},
|
||||
site: {
|
||||
publicPath: '/<%= name %>/',
|
||||
},
|
||||
},
|
||||
site: {
|
||||
title: '<%= name %>',
|
||||
logo: 'https://img.yzcdn.cn/vant/logo.png',
|
||||
nav: [
|
||||
{
|
||||
title: '开发指南',
|
||||
items: [
|
||||
{
|
||||
path: 'home',
|
||||
title: '介绍',
|
||||
},
|
||||
{
|
||||
path: 'quickstart',
|
||||
title: '快速上手',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '基础组件',
|
||||
items: [
|
||||
{
|
||||
path: 'demo-button',
|
||||
title: 'DemoButton 按钮',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
45
vant/packages/create-vant-cli-app/package.json
Normal file
45
vant/packages/create-vant-cli-app/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "create-vant-cli-app",
|
||||
"version": "0.1.1",
|
||||
"description": "Create Vant Cli App",
|
||||
"main": "lib/index.js",
|
||||
"bin": {
|
||||
"create-vant-cli-app": "./lib/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "tsc --watch",
|
||||
"release": "tsc & release-it"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/youzan/vant/tree/dev/packages/create-vant-cli-app"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"generators"
|
||||
],
|
||||
"keywords": [
|
||||
"vant"
|
||||
],
|
||||
"author": "chenjiahan",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^8.0.1",
|
||||
"@types/yeoman-generator": "^3.1.4",
|
||||
"release-it": "^12.4.3",
|
||||
"typescript": "^3.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^3.0.0",
|
||||
"consola": "^2.11.3",
|
||||
"fs-extra": "^8.1.0",
|
||||
"inquirer": "^7.0.3",
|
||||
"yeoman-generator": "^4.4.0"
|
||||
},
|
||||
"release-it": {
|
||||
"git": {
|
||||
"tag": false,
|
||||
"commitMessage": "chore: release create-vant-cli-app@${version}"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
vant/packages/create-vant-cli-app/src/.pydio
Normal file
1
vant/packages/create-vant-cli-app/src/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
581186e1-63af-4a90-a85a-f0f17ad1c9b7
|
||||
4
vant/packages/create-vant-cli-app/src/constant.ts
Normal file
4
vant/packages/create-vant-cli-app/src/constant.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { join } from 'path';
|
||||
|
||||
export const CWD = process.cwd();
|
||||
export const GENERATOR_DIR = join(__dirname, '../generators');
|
||||
92
vant/packages/create-vant-cli-app/src/generator.ts
Normal file
92
vant/packages/create-vant-cli-app/src/generator.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import chalk from 'chalk';
|
||||
import consola from 'consola';
|
||||
import { join } from 'path';
|
||||
import { CWD, GENERATOR_DIR } from './constant';
|
||||
import Generator from 'yeoman-generator';
|
||||
|
||||
const TEMPLATES = join(GENERATOR_DIR, 'templates');
|
||||
const PROMPTS = [
|
||||
{
|
||||
name: 'preprocessor',
|
||||
message: 'Select css preprocessor',
|
||||
type: 'list',
|
||||
choices: ['Less', 'Sass'],
|
||||
},
|
||||
];
|
||||
|
||||
export class VanGenerator extends Generator {
|
||||
inputs = {
|
||||
name: '',
|
||||
cssLang: '',
|
||||
preprocessor: '',
|
||||
};
|
||||
|
||||
constructor(name: string) {
|
||||
super([], {
|
||||
env: {
|
||||
cwd: join(CWD, name),
|
||||
},
|
||||
resolved: GENERATOR_DIR,
|
||||
});
|
||||
|
||||
this.inputs.name = name;
|
||||
}
|
||||
|
||||
async prompting() {
|
||||
return this.prompt<Record<string, string>>(PROMPTS).then(inputs => {
|
||||
const preprocessor = inputs.preprocessor.toLowerCase();
|
||||
const cssLang = preprocessor === 'sass' ? 'scss' : preprocessor;
|
||||
|
||||
this.inputs.cssLang = cssLang;
|
||||
this.inputs.preprocessor = preprocessor;
|
||||
});
|
||||
}
|
||||
|
||||
writing() {
|
||||
consola.info(`Creating project in ${join(CWD, this.inputs.name)}\n`);
|
||||
|
||||
const copy = (from: string, to?: string) => {
|
||||
this.fs.copy(join(TEMPLATES, from), this.destinationPath(to || from));
|
||||
};
|
||||
|
||||
const copyTpl = (from: string, to?: string) => {
|
||||
this.fs.copyTpl(
|
||||
join(TEMPLATES, from),
|
||||
this.destinationPath(to || from),
|
||||
this.inputs
|
||||
);
|
||||
};
|
||||
|
||||
copyTpl('package.json.tpl', 'package.json');
|
||||
copyTpl('vant.config.js');
|
||||
copyTpl('src/**/*', 'src');
|
||||
copyTpl('docs/**/*', 'docs');
|
||||
copy('babel.config.js');
|
||||
copy('gitignore.tpl', '.gitignore');
|
||||
copy('eslintignore.tpl', '.eslintignore');
|
||||
}
|
||||
|
||||
install() {
|
||||
console.log();
|
||||
consola.info('Install dependencies...\n');
|
||||
|
||||
process.chdir(this.inputs.name);
|
||||
|
||||
this.installDependencies({
|
||||
npm: false,
|
||||
bower: false,
|
||||
yarn: true,
|
||||
skipMessage: true,
|
||||
});
|
||||
}
|
||||
|
||||
end() {
|
||||
const { name } = this.inputs;
|
||||
|
||||
console.log();
|
||||
consola.success(`Successfully created ${chalk.yellow(name)}.`);
|
||||
consola.success(
|
||||
`Run ${chalk.yellow(`cd ${name} && yarn dev`)} to start development!`
|
||||
);
|
||||
}
|
||||
}
|
||||
24
vant/packages/create-vant-cli-app/src/index.ts
Normal file
24
vant/packages/create-vant-cli-app/src/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import { ensureDir } from 'fs-extra';
|
||||
import { VanGenerator } from './generator';
|
||||
|
||||
const PROMPTS = [
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'Your package name',
|
||||
},
|
||||
];
|
||||
|
||||
export default async function run() {
|
||||
const { name } = await inquirer.prompt(PROMPTS);
|
||||
|
||||
ensureDir(name);
|
||||
|
||||
const generator = new VanGenerator(name);
|
||||
generator.run();
|
||||
}
|
||||
|
||||
run();
|
||||
13
vant/packages/create-vant-cli-app/tsconfig.json
Normal file
13
vant/packages/create-vant-cli-app/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"outDir": "./lib",
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["esnext"]
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
3379
vant/packages/create-vant-cli-app/yarn.lock
Normal file
3379
vant/packages/create-vant-cli-app/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
vant/packages/vant-cli/.pydio
Normal file
1
vant/packages/vant-cli/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
eae5cd50-ee35-417d-97f7-d71db803b004
|
||||
103
vant/packages/vant-cli/README.md
Normal file
103
vant/packages/vant-cli/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Vant Cli
|
||||
|
||||
Vant Cli 是一个 Vue 组件库构建工具,通过 Vant Cli 可以快速搭建一套功能完备的 Vue 组件库。
|
||||
|
||||
### 特性
|
||||
|
||||
- 提供丰富的命令,涵盖从开发测试到构建发布的完整流程
|
||||
- 基于约定的目录结构,自动生成优雅的文档站点和组件示例
|
||||
- 内置 ESlint、Stylelint 校验规则,提交代码时自动执行校验
|
||||
- 构建后的组件库默认支持按需引入、主题定制、Tree Shaking
|
||||
|
||||
### 快速上手
|
||||
|
||||
执行以下命令可以快速创建一个基于 Vant Cli 的项目:
|
||||
|
||||
```bash
|
||||
npx create-vant-cli-app
|
||||
```
|
||||
|
||||
### 手动安装
|
||||
|
||||
```shell
|
||||
# 通过 npm 安装
|
||||
npm i @vant/cli -D
|
||||
|
||||
# 通过 yarn 安装
|
||||
yarn add @vant/cli --dev
|
||||
```
|
||||
|
||||
安装完成后,请将以下配置添加到 package.json 文件中
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "vant-cli dev",
|
||||
"test": "vant-cli test",
|
||||
"lint": "vant-cli lint",
|
||||
"release": "vant-cli release",
|
||||
"build-site": "vant-cli build-site"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged",
|
||||
"commit-msg": "vant commit-lint"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx,js,jsx,vue}": [
|
||||
"eslint",
|
||||
"git add"
|
||||
],
|
||||
"*.{vue,css,less,scss}": [
|
||||
"stylelint",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"extends": ["@vant"]
|
||||
},
|
||||
"stylelint": {
|
||||
"extends": ["@vant/stylelint-config"]
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
},
|
||||
"browserslist": ["Android >= 4.0", "iOS >= 8"]
|
||||
}
|
||||
```
|
||||
|
||||
## 命令
|
||||
|
||||
### dev
|
||||
|
||||
本地开发,dev 命令会启动一个本地服务器,用于在开发过程中对文档和示例进行预览
|
||||
|
||||
### build
|
||||
|
||||
构建组件库,在`es`和`lib`目录生成可用于生产环境的组件代码
|
||||
|
||||
### build-site
|
||||
|
||||
构建文档站点,在`site`目录生成可用于生产环境的文档站点代码
|
||||
|
||||
### release
|
||||
|
||||
发布组件库,发布前会自动执行 build 和 changelog 命令
|
||||
|
||||
### changelog
|
||||
|
||||
基于 commit 记录生成更新日志
|
||||
|
||||
### commit-lint
|
||||
|
||||
校验 commit message 的格式是否符合规范,需要配合`husky`在提交 commit 时触发
|
||||
|
||||
## 配置
|
||||
|
||||
参见[配置指南](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/config.md)。
|
||||
|
||||
## 更新日志
|
||||
|
||||
参见[更新日志](https://github.com/youzan/vant/tree/dev/packages/vant-cli/changelog.md)。
|
||||
80
vant/packages/vant-cli/changelog.md
Normal file
80
vant/packages/vant-cli/changelog.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 更新日志
|
||||
|
||||
### [v2.2.2]
|
||||
`2020-02-05`
|
||||
|
||||
- 修复在 windows 上获取 markdown 路径错误的问题 ([#5626](https://github.com/youzan/vant/pull/5626))
|
||||
|
||||
|
||||
### [v2.2.1]
|
||||
`2020-02-04`
|
||||
|
||||
- 升级 babel@7.8
|
||||
- 修复切换版本时跳转 undefined 的问题 ([#5620](https://github.com/youzan/vant/pull/5620))
|
||||
|
||||
|
||||
### [v2.2.0]
|
||||
`2020-01-19`
|
||||
|
||||
- 升级 @vant/eslint-config@2.0.0
|
||||
|
||||
|
||||
### [v2.1.8]
|
||||
`2020-01-18`
|
||||
|
||||
- 新增 create-vant-cli-app 初始化命令
|
||||
- 新增 --version 选项
|
||||
- 优化站点导航栏颜色
|
||||
- 优化站点代码块颜色
|
||||
|
||||
|
||||
### [v2.1.7]
|
||||
`2020-01-15`
|
||||
|
||||
- 优化 help 命令
|
||||
- 优化控制台输出信息
|
||||
|
||||
|
||||
### [v2.1.6]
|
||||
`2020-01-12`
|
||||
|
||||
- 支持自定义 Postcss 配置
|
||||
- 支持自定义 devServer 端口
|
||||
- 优化文档站点的 meta 字段
|
||||
- 新增 API 文档中的版本标签样式
|
||||
|
||||
|
||||
### [v2.1.5]
|
||||
`2020-01-10`
|
||||
|
||||
- 修复编译时未替换 import 语句中的 CSS 后缀的问题
|
||||
- 升级 husky 版本到 4.0
|
||||
|
||||
|
||||
### [v2.1.4]
|
||||
`2020-01-06`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- 锁死 @vue/test-utils 版本为 1.0.0-beta.29
|
||||
|
||||
|
||||
### [v2.1.3]
|
||||
`2020-01-06`
|
||||
|
||||
**Feature**
|
||||
|
||||
- 增加 cache-loader,提高构建速度
|
||||
- 调整 jest setup 文件执行时机,延迟至 env 初始化后执行
|
||||
|
||||
|
||||
### [v2.1.2]
|
||||
`2020-01-05`
|
||||
|
||||
**Feature**
|
||||
|
||||
- 优化文档站点样式,统一圆角大小
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- 修复 windows 下路径分隔符错误的问题
|
||||
1
vant/packages/vant-cli/docs/.pydio
Normal file
1
vant/packages/vant-cli/docs/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
06942dbd-1253-44af-9a0b-4f339317d63d
|
||||
288
vant/packages/vant-cli/docs/config.md
Normal file
288
vant/packages/vant-cli/docs/config.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# 配置指南
|
||||
|
||||
- [配置指南](#)
|
||||
- [vant.config.js](#vantconfigjs)
|
||||
- [name](#name)
|
||||
- [build.css](#buildcss)
|
||||
- [build.site](#buildsite)
|
||||
- [site.title](#sitetitle)
|
||||
- [site.logo](#sitelogo)
|
||||
- [site.description](#sitedescription)
|
||||
- [site.nav](#sitenav)
|
||||
- [site.versions](#siteversions)
|
||||
- [site.baiduAnalytics](#sitebaiduanalytics)
|
||||
- [Webpack](#webpack)
|
||||
- [Babel](#babel)
|
||||
- [默认配置](#-1)
|
||||
- [依赖](#-2)
|
||||
- [Postcss](#postcss)
|
||||
- [默认配置](#-3)
|
||||
- [browserslist](#browserslist)
|
||||
|
||||
## vant.config.js
|
||||
|
||||
`vant.config.js`中包含了`vant-cli`的打包配置和文档站点配置,请创建此文件并置于项目根目录下。下面是一份基本配置的示例:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// 组件库名称
|
||||
name: 'demo-ui',
|
||||
// 构建配置
|
||||
build: {
|
||||
site: {
|
||||
publicPath: '/demo-ui/'
|
||||
}
|
||||
},
|
||||
// 文档站点配置
|
||||
site: {
|
||||
// 标题
|
||||
title: 'Demo UI',
|
||||
// 图标
|
||||
logo: 'https://img.yzcdn.cn/vant/logo.png',
|
||||
// 描述
|
||||
description: '示例组件库',
|
||||
// 左侧导航
|
||||
nav: [
|
||||
{
|
||||
title: '开发指南',
|
||||
items: [
|
||||
{
|
||||
path: 'home',
|
||||
title: '介绍'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '基础组件',
|
||||
items: [
|
||||
{
|
||||
path: 'my-button',
|
||||
title: 'MyButton 按钮'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### name
|
||||
|
||||
- Type: `string`
|
||||
- Default: `''`
|
||||
|
||||
组件库名称,建议使用中划线分割,如`demo-ui`。
|
||||
|
||||
### build.css
|
||||
|
||||
- Type: `object`
|
||||
- Default: `{ preprocessor: 'less' }`
|
||||
|
||||
CSS 预处理器配置,目前支持`less`和`sass`两种预处理器,默认使用`less`。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
build: {
|
||||
css: {
|
||||
preprocessor: 'sass'
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### build.site
|
||||
|
||||
- Type: `object`
|
||||
- Default: `{ publicPath: '/' }`
|
||||
|
||||
`site.publicPath`等价于 webpack 的`output.publicPath`配置。
|
||||
|
||||
一般来说,我们的文档网站会部署在一个域名的子路径上,如 `https://my.github.io/demo-ui/`,这时候`publicPath`需要跟子路径保持一致,即`/demo-ui/`。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
build: {
|
||||
site: {
|
||||
publicPath: '/demo-ui/'
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### site.title
|
||||
|
||||
- Type: `string`
|
||||
- Default: `''`
|
||||
|
||||
文档站点的标题。
|
||||
|
||||
### site.logo
|
||||
|
||||
- Type: `string`
|
||||
- Default: `''`
|
||||
|
||||
文档站点的 Logo。
|
||||
|
||||
### site.description
|
||||
|
||||
- Type: `string`
|
||||
- Default: `''`
|
||||
|
||||
标题下方的描述文案。
|
||||
|
||||
### site.nav
|
||||
|
||||
- Type: `object[]`
|
||||
- Default: `undefined`
|
||||
|
||||
文档站点的左侧导航,数组中的每个对象表示一个导航分组。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
site: {
|
||||
nav: [
|
||||
{
|
||||
// 分组标题
|
||||
title: '开发指南',
|
||||
// 导航项
|
||||
items: [
|
||||
{
|
||||
// 导航项路由
|
||||
path: 'home',
|
||||
// 导航项文案
|
||||
title: '介绍'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### site.versions
|
||||
|
||||
- Type: `object[]`
|
||||
- Default: `undefined`
|
||||
|
||||
文档站点多版本配置,当组件库存在多个版本的文档时,可以通过`site.versions`在顶部导航配置一个版本切换按钮。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
site: {
|
||||
versions: [
|
||||
{
|
||||
label: '1.x',
|
||||
link: 'https://youzan.github.io/vant/1.x/'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### site.baiduAnalytics
|
||||
|
||||
- Type: `object`
|
||||
- Default: `undefied`
|
||||
|
||||
文档网站的百度统计配置,添加这项配置后,会自动在构建文档网站时加载百度统计的脚本。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
site: {
|
||||
baiduAnalytics: {
|
||||
// 打开百度统计 ->『管理』->『代码获取』
|
||||
// 找到下面这串 URL: "https://hm.baidu.com/hm.js?xxxxx"
|
||||
// 将 `xxxxx` 填写在 seed 中即可
|
||||
seed: 'xxxxx'
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Webpack
|
||||
|
||||
通过根目录下的`webpack.config.js`文件可以修改 Webpack 配置,配置内容会通过 [webpack-merge](https://github.com/survivejs/webpack-merge) 合并到最终的配置中。
|
||||
|
||||
比如修改 devServer 端口:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
devServer: {
|
||||
port: 9000
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Babel
|
||||
|
||||
通过根目录下的`babel.config.js`文件可以对 Babel 进行配置。
|
||||
|
||||
### 默认配置
|
||||
|
||||
推荐使用`vant-cli`内置的 preset,配置如下:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
presets: ['@vant/cli/preset']
|
||||
};
|
||||
```
|
||||
|
||||
`@vant/cli/preset`中默认包含了以下插件:
|
||||
|
||||
- @babel/preset-env(不含 core-js)
|
||||
- @babel/preset-typescript
|
||||
- @babel/plugin-transform-runtime
|
||||
- @babel/plugin-transform-object-assign
|
||||
- @babel/plugin-proposal-optional-chaining
|
||||
- @babel/plugin-proposal-nullish-coalescing-operator
|
||||
- @vue/babel-preset-jsx
|
||||
|
||||
### 依赖
|
||||
|
||||
由于使用了`@babel/plugin-transform-runtime`来优化 Babel 的 helper 函数,你需要将`@babel/runtime`添加到`package.json`的依赖项:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.x"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果使用了 JSX 的语法,还需要将`@vue/babel-helper-vue-jsx-merge-props`添加到依赖中:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Postcss
|
||||
|
||||
通过根目录下的`postcss.config.js`文件可以对 Postcss 进行配置。
|
||||
|
||||
### 默认配置
|
||||
|
||||
`vant-cli`中默认的 Postcss 配置如下:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## browserslist
|
||||
|
||||
推荐在`package.json`文件里添加 browserslist 字段,这个值会被`@babel/preset-env`和`autoprefixer`用来确定目标浏览器的版本,保证编译后代码的兼容性。
|
||||
|
||||
在移动端浏览器中使用,可以添加如下配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"browserslist": ["Android >= 4.0", "iOS >= 8"]
|
||||
}
|
||||
```
|
||||
124
vant/packages/vant-cli/package.json
Normal file
124
vant/packages/vant-cli/package.json
Normal file
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"name": "@vant/cli",
|
||||
"version": "2.2.2",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"typings": "lib/index.d.ts",
|
||||
"bin": {
|
||||
"vant-cli": "./lib/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "tsc --watch",
|
||||
"release": "tsc & release-it"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"site",
|
||||
"template",
|
||||
"preset.js"
|
||||
],
|
||||
"keywords": [
|
||||
"vant"
|
||||
],
|
||||
"author": "chenjiahan",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"vue": "^2.5.22",
|
||||
"vue-template-compiler": "^2.5.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^8.0.1",
|
||||
"@types/html-webpack-plugin": "^3.2.2",
|
||||
"@types/lodash": "^4.14.149",
|
||||
"@types/postcss-load-config": "^2.0.1",
|
||||
"@types/sass": "^1.16.0",
|
||||
"@types/shelljs": "^0.8.6",
|
||||
"@types/webpack": "^4.41.4",
|
||||
"@types/webpack-dev-server": "^3.10.0",
|
||||
"@types/webpack-merge": "^4.1.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.8.4",
|
||||
"@babel/plugin-syntax-jsx": "^7.8.3",
|
||||
"@babel/plugin-transform-object-assign": "^7.8.3",
|
||||
"@babel/plugin-transform-runtime": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"@babel/preset-typescript": "^7.8.3",
|
||||
"@nuxt/friendly-errors-webpack-plugin": "^2.5.0",
|
||||
"@types/jest": "^25.1.1",
|
||||
"@vant/eslint-config": "^2.0.0",
|
||||
"@vant/markdown-loader": "^2.3.0",
|
||||
"@vant/markdown-vetur": "^1.1.0",
|
||||
"@vant/stylelint-config": "^1.1.0",
|
||||
"@vant/touch-emulator": "^1.2.0",
|
||||
"@vue/babel-preset-jsx": "^1.1.2",
|
||||
"@vue/component-compiler-utils": "^3.1.1",
|
||||
"@vue/test-utils": "1.0.0-beta.29",
|
||||
"address": "^1.1.2",
|
||||
"autoprefixer": "^9.7.4",
|
||||
"babel-jest": "^25.1.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"cache-loader": "^4.1.0",
|
||||
"chokidar": "^3.3.1",
|
||||
"clean-css": "^4.2.3",
|
||||
"codecov": "^3.6.4",
|
||||
"commander": "^4.1.1",
|
||||
"consola": "^2.11.3",
|
||||
"conventional-changelog": "^3.1.18",
|
||||
"cross-env": "^7.0.0",
|
||||
"css-loader": "^3.4.2",
|
||||
"eslint": "^6.8.0",
|
||||
"fast-glob": "^3.1.1",
|
||||
"gh-pages": "2.0.1",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"husky": "^4.2.1",
|
||||
"jest": "^25.1.0",
|
||||
"jest-canvas-mock": "^2.2.0",
|
||||
"jest-serializer-vue": "^2.0.2",
|
||||
"less": "^3.10.3",
|
||||
"less-loader": "^5.0.0",
|
||||
"lint-staged": "^10.0.7",
|
||||
"lodash": "^4.17.15",
|
||||
"ora": "^4.0.3",
|
||||
"portfinder": "^1.0.25",
|
||||
"postcss": "^7.0.26",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"release-it": "^12.4.3",
|
||||
"sass": "^1.25.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"shelljs": "^0.8.3",
|
||||
"style-loader": "^1.1.3",
|
||||
"stylelint": "^13.0.0",
|
||||
"typescript": "^3.7.5",
|
||||
"vue-jest": "4.0.0-beta.2",
|
||||
"vue-loader": "^15.8.3",
|
||||
"vue-router": "^3.1.5",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-dev-server": "3.10.2",
|
||||
"webpack-merge": "^4.2.2",
|
||||
"webpackbar": "^4.0.0"
|
||||
},
|
||||
"release-it": {
|
||||
"git": {
|
||||
"tag": false,
|
||||
"commitMessage": "chore: release @vant/cli@${version}"
|
||||
}
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"extends": [
|
||||
"@vant"
|
||||
],
|
||||
"rules": {
|
||||
"global-require": 0,
|
||||
"import/no-dynamic-require": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
3
vant/packages/vant-cli/preset.js
Normal file
3
vant/packages/vant-cli/preset.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const babelConfig = require('./lib/config/babel.config');
|
||||
|
||||
module.exports = api => babelConfig(api);
|
||||
1
vant/packages/vant-cli/site/.pydio
Normal file
1
vant/packages/vant-cli/site/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
58a0e612-6925-4750-9303-c27fbbc62ff6
|
||||
1
vant/packages/vant-cli/site/common/.pydio
Normal file
1
vant/packages/vant-cli/site/common/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2c196b31-1743-44f5-bc79-6d655593b8ad
|
||||
29
vant/packages/vant-cli/site/common/iframe-router.js
Normal file
29
vant/packages/vant-cli/site/common/iframe-router.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 同步父窗口和 iframe 的 vue-router 状态
|
||||
*/
|
||||
|
||||
import { iframeReady, isMobile } from '.';
|
||||
|
||||
window.syncPath = function() {
|
||||
const router = window.vueRouter;
|
||||
const isInIframe = window !== window.top;
|
||||
const currentDir = router.history.current.path;
|
||||
|
||||
if (isInIframe) {
|
||||
window.top.replacePath(currentDir);
|
||||
} else if (!isMobile) {
|
||||
const iframe = document.querySelector('iframe');
|
||||
if (iframe) {
|
||||
iframeReady(iframe, () => {
|
||||
iframe.contentWindow.replacePath(currentDir);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.replacePath = function(path = '') {
|
||||
// should preserve hash for anchor
|
||||
if (window.vueRouter.currentRoute.path !== path) {
|
||||
window.vueRouter.replace(path).catch(() => {});
|
||||
}
|
||||
};
|
||||
30
vant/packages/vant-cli/site/common/index.js
Normal file
30
vant/packages/vant-cli/site/common/index.js
Normal file
@@ -0,0 +1,30 @@
|
||||
function iframeReady(iframe, callback) {
|
||||
const doc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
const interval = () => {
|
||||
if (iframe.contentWindow.replacePath) {
|
||||
callback();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
interval();
|
||||
}, 50);
|
||||
}
|
||||
};
|
||||
|
||||
if (doc.readyState === 'complete') {
|
||||
interval();
|
||||
} else {
|
||||
iframe.onload = interval;
|
||||
}
|
||||
}
|
||||
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
const isMobile = /ios|iphone|ipod|ipad|android/.test(ua);
|
||||
|
||||
export function decamelize(str, sep = '-') {
|
||||
return str
|
||||
.replace(/([a-z\d])([A-Z])/g, '$1' + sep + '$2')
|
||||
.replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + sep + '$2')
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export { isMobile, iframeReady };
|
||||
30
vant/packages/vant-cli/site/common/locales.js
Normal file
30
vant/packages/vant-cli/site/common/locales.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const ZH_CN = 'zh-CN';
|
||||
const EN_US = 'en-US';
|
||||
const CACHE_KEY = 'vant-cli-lang';
|
||||
|
||||
let currentLang = ZH_CN;
|
||||
|
||||
export function getLang() {
|
||||
return currentLang;
|
||||
}
|
||||
|
||||
export function setLang(lang) {
|
||||
currentLang = lang;
|
||||
localStorage.setItem(CACHE_KEY, lang);
|
||||
}
|
||||
|
||||
export function setDefaultLang(langFromConfig) {
|
||||
const cached = localStorage.getItem(CACHE_KEY);
|
||||
|
||||
if (cached) {
|
||||
currentLang = cached;
|
||||
return;
|
||||
}
|
||||
|
||||
if (navigator.language && navigator.language.indexOf('zh-') !== -1) {
|
||||
currentLang = ZH_CN;
|
||||
return;
|
||||
}
|
||||
|
||||
currentLang = langFromConfig || EN_US;
|
||||
}
|
||||
1
vant/packages/vant-cli/site/common/style/.pydio
Normal file
1
vant/packages/vant-cli/site/common/style/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
bec7060d-dbcd-4465-b730-de9b5ccae70a
|
||||
46
vant/packages/vant-cli/site/common/style/base.less
Normal file
46
vant/packages/vant-cli/site/common/style/base.less
Normal file
@@ -0,0 +1,46 @@
|
||||
@import './var';
|
||||
|
||||
body {
|
||||
min-width: 1100px;
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
color: @van-doc-black;
|
||||
font-size: 16px;
|
||||
font-family: PingFang SC, 'Helvetica Neue', Arial, sans-serif;
|
||||
background-color: @van-doc-background-color;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.van-doc-row {
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: @van-doc-row-max-width) {
|
||||
width: @van-doc-row-max-width;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
79
vant/packages/vant-cli/site/common/style/highlight.less
Normal file
79
vant/packages/vant-cli/site/common/style/highlight.less
Normal file
@@ -0,0 +1,79 @@
|
||||
@import './var';
|
||||
|
||||
code {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
overflow-x: auto;
|
||||
color: @van-doc-code-color;
|
||||
font-weight: 400;
|
||||
font-size: 13.4px;
|
||||
font-family: @van-doc-code-font-family;
|
||||
line-height: 26px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
-webkit-font-smoothing: auto;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
padding: 0.5em;
|
||||
overflow-x: auto;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.hljs-subst {
|
||||
color: @van-doc-code-color;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-meta,
|
||||
.hljs-symbol,
|
||||
.hljs-template-tag,
|
||||
.hljs-template-variable,
|
||||
.hljs-addition {
|
||||
color: @van-doc-green;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.hljs-params,
|
||||
.hljs-keyword,
|
||||
.hljs-attribute {
|
||||
color: @van-doc-purple;
|
||||
}
|
||||
|
||||
.hljs-deletion,
|
||||
.hljs-variable,
|
||||
.hljs-number,
|
||||
.hljs-regexp,
|
||||
.hljs-literal,
|
||||
.hljs-bullet,
|
||||
.hljs-link {
|
||||
color: #eb6f6f;
|
||||
}
|
||||
|
||||
.hljs-attr,
|
||||
.hljs-selector-tag,
|
||||
.hljs-title,
|
||||
.hljs-section,
|
||||
.hljs-built_in,
|
||||
.hljs-doctag,
|
||||
.hljs-type,
|
||||
.hljs-name,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-strong {
|
||||
color: #4994df;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
29
vant/packages/vant-cli/site/common/style/var.less
Normal file
29
vant/packages/vant-cli/site/common/style/var.less
Normal file
@@ -0,0 +1,29 @@
|
||||
@van-doc-black: #323233;
|
||||
@van-doc-blue: #1989fa;
|
||||
@van-doc-purple: #8080ff;
|
||||
@van-doc-fuchsia: #a7419e;
|
||||
@van-doc-green: #4fc08d;
|
||||
@van-doc-text-color: #34495e;
|
||||
@van-doc-text-light-blue: rgba(69, 90, 100, 0.6);
|
||||
@van-doc-background-color: #f7f8fa;
|
||||
@van-doc-grey: #999;
|
||||
@van-doc-dark-grey: #666;
|
||||
@van-doc-light-grey: #ccc;
|
||||
@van-doc-border-color: #f1f4f8;
|
||||
@van-doc-code-color: #58727e;
|
||||
@van-doc-code-background-color: #f1f4f8;
|
||||
@van-doc-code-font-family: 'Source Code Pro', 'Monaco', 'Inconsolata', monospace;
|
||||
@van-doc-padding: 30px;
|
||||
@van-doc-row-max-width: 1680px;
|
||||
@van-doc-nav-width: 220px;
|
||||
@van-doc-border-radius: 12px;
|
||||
|
||||
// header
|
||||
@van-doc-header-top-height: 60px;
|
||||
@van-doc-header-bottom-height: 50px;
|
||||
|
||||
// simulator
|
||||
@van-doc-simulator-width: 360px;
|
||||
@van-doc-simulator-small-width: 320px;
|
||||
@van-doc-simulator-height: 620px;
|
||||
@van-doc-simulator-small-height: 560px;
|
||||
1
vant/packages/vant-cli/site/desktop/.pydio
Normal file
1
vant/packages/vant-cli/site/desktop/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
a19e2525-f848-4240-a0b0-be63b37c9f6b
|
||||
105
vant/packages/vant-cli/site/desktop/App.vue
Normal file
105
vant/packages/vant-cli/site/desktop/App.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div class="app">
|
||||
<van-doc
|
||||
:lang="lang"
|
||||
:config="config"
|
||||
:versions="versions"
|
||||
:simulator="simulator"
|
||||
:lang-configs="langConfigs"
|
||||
>
|
||||
<router-view />
|
||||
</van-doc>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VanDoc from './components';
|
||||
import { config, packageVersion } from 'site-desktop-shared';
|
||||
import { setLang } from '../common/locales';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VanDoc,
|
||||
},
|
||||
|
||||
data() {
|
||||
const path = location.pathname.replace('/index', '/');
|
||||
|
||||
return {
|
||||
packageVersion,
|
||||
simulator: `${path}mobile.html${location.hash}`,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
lang() {
|
||||
const { lang } = this.$route.meta;
|
||||
return lang || '';
|
||||
},
|
||||
|
||||
langConfigs() {
|
||||
const { locales = {} } = config.site;
|
||||
return Object.keys(locales).map(key => ({
|
||||
lang: key,
|
||||
label: locales[key].langLabel || '',
|
||||
}));
|
||||
},
|
||||
|
||||
config() {
|
||||
const { locales } = config.site;
|
||||
|
||||
if (locales) {
|
||||
return locales[this.lang];
|
||||
}
|
||||
|
||||
return config.site;
|
||||
},
|
||||
|
||||
versions() {
|
||||
if (config.site.versions) {
|
||||
return [{ label: packageVersion }, ...config.site.versions];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
lang(val) {
|
||||
setLang(val);
|
||||
this.setTitle();
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.setTitle();
|
||||
},
|
||||
|
||||
methods: {
|
||||
setTitle() {
|
||||
let { title } = this.config;
|
||||
|
||||
if (this.config.description) {
|
||||
title += ` - ${this.config.description}`;
|
||||
}
|
||||
|
||||
document.title = title;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../common/style/base';
|
||||
@import '../common/style/highlight';
|
||||
|
||||
.van-doc-intro {
|
||||
padding-top: 20px;
|
||||
font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1
vant/packages/vant-cli/site/desktop/components/.pydio
Normal file
1
vant/packages/vant-cli/site/desktop/components/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
aee38061-e7df-40fa-b330-e3c710239aa2
|
||||
32
vant/packages/vant-cli/site/desktop/components/Container.vue
Normal file
32
vant/packages/vant-cli/site/desktop/components/Container.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div
|
||||
class="van-doc-container van-doc-row"
|
||||
:class="{ 'van-doc-container--with-simulator': hasSimulator }"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'van-doc-container',
|
||||
|
||||
props: {
|
||||
hasSimulator: Boolean,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.van-doc-container {
|
||||
box-sizing: border-box;
|
||||
padding-left: @van-doc-nav-width;
|
||||
overflow: hidden;
|
||||
|
||||
&--with-simulator {
|
||||
padding-right: @van-doc-simulator-width + @van-doc-padding;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
238
vant/packages/vant-cli/site/desktop/components/Content.vue
Normal file
238
vant/packages/vant-cli/site/desktop/components/Content.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div :class="['van-doc-content', `van-doc-content--${currentPage}`]">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'van-doc-content',
|
||||
|
||||
computed: {
|
||||
currentPage() {
|
||||
const { path } = this.$route;
|
||||
if (path) {
|
||||
return path.split('/').slice(-1)[0];
|
||||
}
|
||||
return this.$route.name;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.van-doc-content {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding: 0 0 75px;
|
||||
|
||||
.card {
|
||||
margin-bottom: 24px;
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
border-radius: @van-doc-border-radius;
|
||||
box-shadow: 0 8px 12px #ebedf0;
|
||||
}
|
||||
|
||||
a {
|
||||
margin: 0 1px;
|
||||
color: @van-doc-green;
|
||||
-webkit-font-smoothing: auto;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: @van-doc-black;
|
||||
font-weight: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
&[id] {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 30px;
|
||||
font-size: 30px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 45px 0 20px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 16px;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 24px 0 12px;
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 24px 0 12px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: @van-doc-text-color;
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
color: @van-doc-text-color;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
border-collapse: collapse;
|
||||
|
||||
th {
|
||||
padding: 8px 10px;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 8px;
|
||||
border-top: 1px solid @van-doc-code-background-color;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
|
||||
// version tag
|
||||
code {
|
||||
margin: 0;
|
||||
padding: 2px 6px;
|
||||
color: @van-doc-blue;
|
||||
font-weight: 500;
|
||||
font-size: 10px;
|
||||
background-color: fade(@van-doc-blue, 10%);
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
em {
|
||||
color: @van-doc-green;
|
||||
font-size: 12.5px;
|
||||
font-family: @van-doc-code-font-family;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: auto;
|
||||
}
|
||||
}
|
||||
|
||||
ul li,
|
||||
ol li {
|
||||
position: relative;
|
||||
margin: 5px 0 5px 10px;
|
||||
padding-left: 15px;
|
||||
color: @van-doc-text-color;
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
box-sizing: border-box;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin-top: 10px;
|
||||
border: 1px solid @van-doc-dark-grey;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 30px 0;
|
||||
border: 0 none;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
p > code,
|
||||
li > code,
|
||||
table code {
|
||||
display: inline;
|
||||
margin: 2px 3px;
|
||||
padding: 2px 5px;
|
||||
font-size: 13px;
|
||||
font-family: inherit;
|
||||
word-break: keep-all;
|
||||
background-color: #f0f2f5;
|
||||
border-radius: 4px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
p > code {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 20px 0 0;
|
||||
padding: 16px;
|
||||
color: rgba(52, 73, 94, 0.8);
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
background-color: #ecf9ff;
|
||||
border-radius: @van-doc-border-radius;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
border-radius: @van-doc-border-radius;
|
||||
}
|
||||
|
||||
&--changelog {
|
||||
strong {
|
||||
display: block;
|
||||
margin: 24px 0 12px;
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
+ p code {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
273
vant/packages/vant-cli/site/desktop/components/Header.vue
Normal file
273
vant/packages/vant-cli/site/desktop/components/Header.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<div class="van-doc-header">
|
||||
<div class="van-doc-row">
|
||||
<div class="van-doc-header__top">
|
||||
<a class="van-doc-header__logo">
|
||||
<img :src="config.logo" />
|
||||
<span>{{ config.title }}</span>
|
||||
</a>
|
||||
|
||||
<search-input
|
||||
v-if="searchConfig"
|
||||
:lang="lang"
|
||||
:search-config="searchConfig"
|
||||
/>
|
||||
|
||||
<ul class="van-doc-header__top-nav">
|
||||
<li v-for="item in config.links" class="van-doc-header__top-nav-item">
|
||||
<a
|
||||
class="van-doc-header__logo-link"
|
||||
target="_blank"
|
||||
:href="item.url"
|
||||
>
|
||||
<img :src="item.logo" />
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li
|
||||
ref="version"
|
||||
v-if="versions"
|
||||
class="van-doc-header__top-nav-item"
|
||||
>
|
||||
<span
|
||||
class="van-doc-header__cube van-doc-header__version"
|
||||
@click="toggleVersionPop"
|
||||
>
|
||||
{{ versions[0].label }}
|
||||
<transition name="van-doc-dropdown">
|
||||
<div v-if="showVersionPop" class="van-doc-header__version-pop">
|
||||
<div
|
||||
v-for="item in versions"
|
||||
class="van-doc-header__version-pop-item"
|
||||
@click="onSwitchVersion(item)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li v-if="langLabel && langLink" class="van-doc-header__top-nav-item">
|
||||
<a class="van-doc-header__cube" :href="langLink">{{ langLabel }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchInput from './SearchInput';
|
||||
|
||||
export default {
|
||||
name: 'van-doc-header',
|
||||
|
||||
components: {
|
||||
SearchInput,
|
||||
},
|
||||
|
||||
props: {
|
||||
lang: String,
|
||||
config: Object,
|
||||
versions: Array,
|
||||
langConfigs: Array,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showVersionPop: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
langLink() {
|
||||
return `#${this.$route.path.replace(this.lang, this.anotherLang.lang)}`;
|
||||
},
|
||||
|
||||
langLabel() {
|
||||
return this.anotherLang.label;
|
||||
},
|
||||
|
||||
anotherLang() {
|
||||
const items = this.langConfigs.filter(item => item.lang !== this.lang);
|
||||
if (items.length) {
|
||||
return items[0];
|
||||
}
|
||||
|
||||
return {};
|
||||
},
|
||||
|
||||
searchConfig() {
|
||||
return this.config.searchConfig;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleVersionPop() {
|
||||
const val = !this.showVersionPop;
|
||||
|
||||
const action = val ? 'add' : 'remove';
|
||||
document.body[`${action}EventListener`](
|
||||
'click',
|
||||
this.checkHideVersionPop
|
||||
);
|
||||
|
||||
this.showVersionPop = val;
|
||||
},
|
||||
|
||||
checkHideVersionPop(event) {
|
||||
if (!this.$refs.version.contains(event.target)) {
|
||||
this.showVersionPop = false;
|
||||
}
|
||||
},
|
||||
|
||||
onSwitchLang(lang) {
|
||||
this.$router.push(this.$route.path.replace(lang.from, lang.to));
|
||||
},
|
||||
|
||||
onSwitchVersion(version) {
|
||||
if (version.link) {
|
||||
location.href = version.link;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.van-doc-header {
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
|
||||
&__top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @van-doc-header-top-height;
|
||||
padding: 0 @van-doc-padding;
|
||||
line-height: @van-doc-header-top-height;
|
||||
background-color: #001938;
|
||||
|
||||
&-nav {
|
||||
flex: 1;
|
||||
font-size: 0;
|
||||
text-align: right;
|
||||
|
||||
> li {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&-item {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__cube {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 0 12px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-family: 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
border: 1px solid rgba(255, 255, 255, 0.7);
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
&__version {
|
||||
padding-right: 20px;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 7px;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
border: 1px solid;
|
||||
border-color: transparent transparent currentColor currentColor;
|
||||
transform: rotate(-45deg);
|
||||
content: '';
|
||||
}
|
||||
|
||||
&-pop {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
color: #333;
|
||||
line-height: 36px;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
border-radius: @van-doc-border-radius;
|
||||
box-shadow: 0 4px 12px #ebedf0;
|
||||
transform-origin: top;
|
||||
transition: 0.2s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
|
||||
&-item {
|
||||
padding-left: 12px;
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: @van-doc-blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
display: block;
|
||||
|
||||
img,
|
||||
span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo-link {
|
||||
img {
|
||||
display: block;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.van-doc-dropdown {
|
||||
&-enter,
|
||||
&-leave-active {
|
||||
transform: scaleY(0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
158
vant/packages/vant-cli/site/desktop/components/Nav.vue
Normal file
158
vant/packages/vant-cli/site/desktop/components/Nav.vue
Normal file
@@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<div class="van-doc-nav" :style="style">
|
||||
<div
|
||||
v-for="(group, index) in navConfig"
|
||||
class="van-doc-nav__group"
|
||||
:key="index"
|
||||
>
|
||||
<div class="van-doc-nav__title">
|
||||
{{ group.title }}
|
||||
</div>
|
||||
<template v-if="group.items">
|
||||
<div
|
||||
v-for="(item, groupIndex) in group.items"
|
||||
:key="groupIndex"
|
||||
class="van-doc-nav__item"
|
||||
>
|
||||
<van-doc-nav-link :item="item" :base="base" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NavLink from './NavLink';
|
||||
|
||||
export default {
|
||||
name: 'van-doc-nav',
|
||||
|
||||
components: {
|
||||
[NavLink.name]: NavLink,
|
||||
},
|
||||
|
||||
props: {
|
||||
lang: String,
|
||||
navConfig: Array,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
top: 60,
|
||||
bottom: 0,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
style() {
|
||||
return {
|
||||
top: this.top + 'px',
|
||||
bottom: this.bottom + 'px',
|
||||
};
|
||||
},
|
||||
|
||||
base() {
|
||||
return this.lang ? `/${this.lang}/` : '/';
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
window.addEventListener('scroll', this.onScroll);
|
||||
this.onScroll();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onScroll() {
|
||||
const { pageYOffset: offset } = window;
|
||||
this.top = Math.max(0, 60 - offset);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.van-doc-nav {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
min-width: @van-doc-nav-width;
|
||||
max-width: @van-doc-nav-width;
|
||||
padding: 24px 0 72px;
|
||||
overflow-y: scroll;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 8px 12px #ebedf0;
|
||||
|
||||
@media (min-width: @van-doc-row-max-width) {
|
||||
left: 50%;
|
||||
margin-left: -(@van-doc-row-max-width / 2);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&:hover::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(69, 90, 100, 0.2);
|
||||
}
|
||||
|
||||
&__group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
padding: 8px 0 8px @van-doc-padding;
|
||||
color: #455a64;
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
a {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 8px 0 8px @van-doc-padding;
|
||||
color: #455a64;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
color: @van-doc-green;
|
||||
}
|
||||
|
||||
&.active {
|
||||
-webkit-font-smoothing: auto;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1300px) {
|
||||
&__item {
|
||||
a {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&:active {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
62
vant/packages/vant-cli/site/desktop/components/NavLink.vue
Normal file
62
vant/packages/vant-cli/site/desktop/components/NavLink.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<router-link
|
||||
v-if="item.path"
|
||||
:class="{ active }"
|
||||
:to="path"
|
||||
v-html="itemName"
|
||||
/>
|
||||
<a v-else-if="item.link" :href="item.link" v-html="itemName" />
|
||||
<a v-else v-html="itemName" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'van-doc-nav-link',
|
||||
|
||||
props: {
|
||||
base: String,
|
||||
item: Object,
|
||||
},
|
||||
|
||||
computed: {
|
||||
itemName() {
|
||||
const name = (this.item.title || this.item.name).split(' ');
|
||||
return `${name[0]} <span>${name.slice(1).join(' ')}</span>`;
|
||||
},
|
||||
|
||||
path() {
|
||||
return `${this.base}${this.item.path}`;
|
||||
},
|
||||
|
||||
active() {
|
||||
if (this.$route.path === this.path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.item.path === 'home') {
|
||||
return this.$route.path === this.base;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
active() {
|
||||
this.scrollIntoView();
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.scrollIntoView();
|
||||
},
|
||||
|
||||
methods: {
|
||||
scrollIntoView() {
|
||||
if (this.active && this.$el && this.$el.scrollIntoViewIfNeeded) {
|
||||
this.$el.scrollIntoViewIfNeeded();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
101
vant/packages/vant-cli/site/desktop/components/SearchInput.vue
Normal file
101
vant/packages/vant-cli/site/desktop/components/SearchInput.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<input class="van-doc-search" :placeholder="placeholder" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'van-doc-search',
|
||||
|
||||
props: {
|
||||
lang: String,
|
||||
searchConfig: Object,
|
||||
},
|
||||
|
||||
computed: {
|
||||
placeholder() {
|
||||
return this.searchConfig.placeholder || 'Search...';
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
lang(lang) {
|
||||
if (this.docsearchInstance) {
|
||||
this.docsearchInstance.algoliaOptions.facetFilters = [`lang:${lang}`];
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.searchConfig) {
|
||||
this.docsearchInstance = window.docsearch({
|
||||
...this.searchConfig,
|
||||
inputSelector: '.van-doc-search',
|
||||
algoliaOptions: {
|
||||
facetFilters: [`lang:${this.lang}`],
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.van-doc-search {
|
||||
width: 200px;
|
||||
height: 60px;
|
||||
margin-left: 140px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: #fff;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-dropdown-menu {
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.algolia-autocomplete {
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
color: @van-doc-blue;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.algolia-docsearch-suggestion--title {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.algolia-docsearch-suggestion--text {
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
box-shadow: inset 0 -1px 0 0 @van-doc-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.algolia-docsearch-suggestion--category-header {
|
||||
border-bottom-color: #eee;
|
||||
}
|
||||
|
||||
.ds-dropdown-menu [class^='ds-dataset-'] {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ds-dropdown-menu {
|
||||
top: 80% !important;
|
||||
box-shadow: 0 4px 12px #ebedf0;
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
82
vant/packages/vant-cli/site/desktop/components/Simulator.vue
Normal file
82
vant/packages/vant-cli/site/desktop/components/Simulator.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div :class="['van-doc-simulator', { 'van-doc-simulator-fixed': isFixed }]">
|
||||
<iframe ref="iframe" :src="src" :style="simulatorStyle" frameborder="0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'van-doc-simulator',
|
||||
|
||||
props: {
|
||||
src: String,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
scrollTop: window.scrollY,
|
||||
windowHeight: window.innerHeight,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isFixed() {
|
||||
return this.scrollTop > 60;
|
||||
},
|
||||
|
||||
simulatorStyle() {
|
||||
const height = Math.min(640, this.windowHeight - 90);
|
||||
return {
|
||||
height: height + 'px',
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
window.addEventListener('scroll', () => {
|
||||
this.scrollTop = window.scrollY;
|
||||
});
|
||||
window.addEventListener('resize', () => {
|
||||
this.windowHeight = window.innerHeight;
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.van-doc-simulator {
|
||||
position: absolute;
|
||||
top: @van-doc-padding + @van-doc-header-top-height;
|
||||
right: @van-doc-padding;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
width: @van-doc-simulator-width;
|
||||
min-width: @van-doc-simulator-width;
|
||||
overflow: hidden;
|
||||
background: #fafafa;
|
||||
border-radius: @van-doc-border-radius;
|
||||
box-shadow: #ebedf0 0 4px 12px;
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
right: auto;
|
||||
left: 750px;
|
||||
}
|
||||
|
||||
@media (min-width: @van-doc-row-max-width) {
|
||||
right: 50%;
|
||||
margin-right: -@van-doc-row-max-width / 2 + 40px;
|
||||
}
|
||||
|
||||
&-fixed {
|
||||
position: fixed;
|
||||
top: @van-doc-padding;
|
||||
}
|
||||
|
||||
iframe {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
108
vant/packages/vant-cli/site/desktop/components/index.vue
Normal file
108
vant/packages/vant-cli/site/desktop/components/index.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="van-doc">
|
||||
<doc-header
|
||||
:lang="lang"
|
||||
:config="config"
|
||||
:versions="versions"
|
||||
:lang-configs="langConfigs"
|
||||
@switch-version="$emit('switch-version', $event)"
|
||||
/>
|
||||
<doc-nav :lang="lang" :nav-config="config.nav" />
|
||||
<doc-container :has-simulator="!!simulator">
|
||||
<doc-content>
|
||||
<slot />
|
||||
</doc-content>
|
||||
</doc-container>
|
||||
<doc-simulator v-if="simulator" :src="simulator" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DocNav from './Nav';
|
||||
import DocHeader from './Header';
|
||||
import DocContent from './Content';
|
||||
import DocContainer from './Container';
|
||||
import DocSimulator from './Simulator';
|
||||
|
||||
export default {
|
||||
name: 'van-doc',
|
||||
|
||||
components: {
|
||||
DocNav,
|
||||
DocHeader,
|
||||
DocContent,
|
||||
DocContainer,
|
||||
DocSimulator,
|
||||
},
|
||||
|
||||
props: {
|
||||
lang: String,
|
||||
versions: Array,
|
||||
simulator: String,
|
||||
langConfigs: Array,
|
||||
config: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
base: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
// eslint-disable-next-line
|
||||
'$route.path'() {
|
||||
this.setNav();
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.setNav();
|
||||
this.keyboardHandler();
|
||||
},
|
||||
|
||||
methods: {
|
||||
setNav() {
|
||||
const { nav } = this.config;
|
||||
const items = nav.reduce((list, item) => list.concat(item.items), []);
|
||||
const currentPath = this.$route.path.split('/').pop();
|
||||
|
||||
let currentIndex;
|
||||
for (let i = 0, len = items.length; i < len; i++) {
|
||||
if (items[i].path === currentPath) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.leftNav = items[currentIndex - 1];
|
||||
this.rightNav = items[currentIndex + 1];
|
||||
},
|
||||
|
||||
keyboardNav(direction) {
|
||||
const nav = direction === 'prev' ? this.leftNav : this.rightNav;
|
||||
if (nav.path) {
|
||||
this.$router.push(this.base + nav.path);
|
||||
}
|
||||
},
|
||||
|
||||
keyboardHandler() {
|
||||
window.addEventListener('keyup', event => {
|
||||
switch (event.keyCode) {
|
||||
case 37: // left
|
||||
this.keyboardNav('prev');
|
||||
break;
|
||||
case 39: // right
|
||||
this.keyboardNav('next');
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
</style>
|
||||
43
vant/packages/vant-cli/site/desktop/index.html
Normal file
43
vant/packages/vant-cli/site/desktop/index.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<meta
|
||||
name="description"
|
||||
content="<%= htmlWebpackPlugin.options.description %>"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="<%= htmlWebpackPlugin.options.logo %>"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
|
||||
/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<% if (htmlWebpackPlugin.options.baiduAnalytics) { %>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement('script');
|
||||
hm.src =
|
||||
'https://hm.baidu.com/hm.js?<%= htmlWebpackPlugin.options.baiduAnalytics.seed %>';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body ontouchstart>
|
||||
<div id="app"></div>
|
||||
<script src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
19
vant/packages/vant-cli/site/desktop/main.js
Normal file
19
vant/packages/vant-cli/site/desktop/main.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App';
|
||||
import { router } from './router';
|
||||
import { scrollToAnchor } from './utils';
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Vue.config.productionTip = false;
|
||||
}
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
mounted() {
|
||||
if (this.$route.hash) {
|
||||
scrollToAnchor(this.$route.hash);
|
||||
}
|
||||
},
|
||||
render: h => h(App),
|
||||
router,
|
||||
});
|
||||
119
vant/packages/vant-cli/site/desktop/router.js
Normal file
119
vant/packages/vant-cli/site/desktop/router.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import Vue from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import { isMobile, decamelize } from '../common';
|
||||
import { config, documents } from 'site-desktop-shared';
|
||||
import { getLang, setDefaultLang } from '../common/locales';
|
||||
import '../common/iframe-router';
|
||||
|
||||
if (isMobile) {
|
||||
location.replace('mobile.html' + location.hash);
|
||||
}
|
||||
|
||||
const { locales, defaultLang } = config.site;
|
||||
|
||||
setDefaultLang(defaultLang);
|
||||
|
||||
function parseName(name) {
|
||||
if (name.indexOf('_') !== -1) {
|
||||
const pairs = name.split('_');
|
||||
const component = pairs.shift();
|
||||
|
||||
return {
|
||||
component: `${decamelize(component)}`,
|
||||
lang: pairs.join('-'),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
component: `${decamelize(name)}`,
|
||||
lang: '',
|
||||
};
|
||||
}
|
||||
|
||||
function getLangFromRoute(route) {
|
||||
const lang = route.path.split('/')[1];
|
||||
const langs = Object.keys(locales);
|
||||
|
||||
if (langs.indexOf(lang) !== -1) {
|
||||
return lang;
|
||||
}
|
||||
|
||||
return getLang();
|
||||
}
|
||||
|
||||
function getRoutes() {
|
||||
const routes = [];
|
||||
const names = Object.keys(documents);
|
||||
|
||||
if (locales) {
|
||||
routes.push({
|
||||
path: '*',
|
||||
redirect: route => `/${getLangFromRoute(route)}/`,
|
||||
});
|
||||
} else {
|
||||
routes.push({
|
||||
path: '*',
|
||||
redirect: '/',
|
||||
});
|
||||
}
|
||||
|
||||
function addHomeRoute(Home, lang) {
|
||||
routes.push({
|
||||
name: lang,
|
||||
path: `/${lang || ''}`,
|
||||
component: Home,
|
||||
meta: { lang },
|
||||
});
|
||||
}
|
||||
|
||||
names.forEach(name => {
|
||||
const { component, lang } = parseName(name);
|
||||
|
||||
if (component === 'home') {
|
||||
addHomeRoute(documents[name], lang);
|
||||
}
|
||||
|
||||
if (lang) {
|
||||
routes.push({
|
||||
name: `${lang}/${component}`,
|
||||
path: `/${lang}/${component}`,
|
||||
component: documents[name],
|
||||
meta: {
|
||||
lang,
|
||||
name: component,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
routes.push({
|
||||
name: `${component}`,
|
||||
path: `/${component}`,
|
||||
component: documents[name],
|
||||
meta: {
|
||||
name: component,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
export const router = new VueRouter({
|
||||
mode: 'hash',
|
||||
routes: getRoutes(),
|
||||
scrollBehavior(to) {
|
||||
if (to.hash) {
|
||||
return { selector: to.hash };
|
||||
}
|
||||
|
||||
return { x: 0, y: 0 };
|
||||
},
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
Vue.nextTick(() => window.syncPath());
|
||||
});
|
||||
|
||||
window.vueRouter = router;
|
||||
19
vant/packages/vant-cli/site/desktop/utils.js
Normal file
19
vant/packages/vant-cli/site/desktop/utils.js
Normal file
@@ -0,0 +1,19 @@
|
||||
export function scrollToAnchor(selector) {
|
||||
let count = 0;
|
||||
|
||||
const timer = setInterval(() => {
|
||||
const el = document.querySelector(selector);
|
||||
if (el) {
|
||||
el.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
});
|
||||
clearInterval(timer);
|
||||
} else {
|
||||
count++;
|
||||
|
||||
if (count > 10) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
1
vant/packages/vant-cli/site/mobile/.pydio
Normal file
1
vant/packages/vant-cli/site/mobile/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
30e8bd7d-e3e2-45e1-92b5-a2f0e3e45b0a
|
||||
30
vant/packages/vant-cli/site/mobile/App.vue
Normal file
30
vant/packages/vant-cli/site/mobile/App.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<demo-nav />
|
||||
<keep-alive>
|
||||
<router-view />
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DemoNav from './components/DemoNav';
|
||||
|
||||
export default {
|
||||
components: { DemoNav },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../common/style/var';
|
||||
@import '../common/style/base';
|
||||
|
||||
body {
|
||||
min-width: 100vw;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
1
vant/packages/vant-cli/site/mobile/components/.pydio
Normal file
1
vant/packages/vant-cli/site/mobile/components/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2ac1d033-d3a3-4e0c-bfd7-d9f0d1b5a9e5
|
||||
12
vant/packages/vant-cli/site/mobile/components/ArrowRight.vue
Normal file
12
vant/packages/vant-cli/site/mobile/components/ArrowRight.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<svg viewBox="0 0 1024 1024">
|
||||
<path
|
||||
fill="#B6C3D2"
|
||||
d="M601.1 556.5L333.8 289.3c-24.5-24.5-24.5-64.6 0-89.1s64.6-24.5 89.1 0l267.3 267.3c24.5 24.5 24.5 64.6 0 89.1-24.5 24.4-64.6 24.4-89.1-.1z"
|
||||
/>
|
||||
<path
|
||||
fill="#B6C3D2"
|
||||
d="M690.2 556.5L422.9 823.8c-24.5 24.5-64.6 24.5-89.1 0s-24.5-64.6 0-89.1l267.3-267.3c24.5-24.5 64.6-24.5 89.1 0 24.5 24.6 24.5 64.6 0 89.1z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
37
vant/packages/vant-cli/site/mobile/components/DemoBlock.vue
Normal file
37
vant/packages/vant-cli/site/mobile/components/DemoBlock.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="van-doc-demo-block">
|
||||
<h2 class="van-doc-demo-block__title">{{ title }}</h2>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'demo-block',
|
||||
|
||||
props: {
|
||||
title: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.van-doc-demo-block {
|
||||
&__title {
|
||||
margin: 0;
|
||||
padding: 32px 16px 16px;
|
||||
color: @van-doc-text-light-blue;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
.van-doc-demo-block__title {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
99
vant/packages/vant-cli/site/mobile/components/DemoHome.vue
Normal file
99
vant/packages/vant-cli/site/mobile/components/DemoHome.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="demo-home">
|
||||
<h1
|
||||
class="demo-home__title"
|
||||
:class="{ 'demo-home__title--small': smallTitle }"
|
||||
>
|
||||
<img :src="config.logo" />
|
||||
<span>{{ config.title }}</span>
|
||||
</h1>
|
||||
<h2 v-if="config.description" class="demo-home__desc">
|
||||
{{ config.description }}
|
||||
</h2>
|
||||
<template v-for="(group, index) in config.nav">
|
||||
<demo-home-nav :group="group" :lang="lang" :key="index" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { config } from 'site-mobile-shared';
|
||||
import DemoHomeNav from './DemoHomeNav';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DemoHomeNav,
|
||||
},
|
||||
|
||||
computed: {
|
||||
lang() {
|
||||
const { lang } = this.$route.meta;
|
||||
return lang;
|
||||
},
|
||||
|
||||
config() {
|
||||
const { locales } = config.site;
|
||||
|
||||
if (locales) {
|
||||
return locales[this.lang];
|
||||
}
|
||||
|
||||
return config.site;
|
||||
},
|
||||
|
||||
smallTitle() {
|
||||
return this.config.title.length >= 8;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.demo-home {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
padding: 46px 20px 20px;
|
||||
background: #fff;
|
||||
|
||||
&__title,
|
||||
&__desc {
|
||||
padding-left: 16px;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin: 0 0 16px;
|
||||
font-size: 32px;
|
||||
|
||||
img,
|
||||
span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&--small {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&__desc {
|
||||
margin: 0 0 40px;
|
||||
color: rgba(69, 90, 100, 0.6);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="demo-home-nav">
|
||||
<div class="demo-home-nav__title">{{ group.title }}</div>
|
||||
<div class="demo-home-nav__group">
|
||||
<router-link
|
||||
class="demo-home-nav__block"
|
||||
v-for="navItem in group.items"
|
||||
:key="navItem.path"
|
||||
:to="`${base}/${navItem.path}`"
|
||||
>
|
||||
{{ navItem.title }}
|
||||
<arrow-right class="demo-home-nav__icon" />
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ArrowRight from './ArrowRight';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ArrowRight,
|
||||
},
|
||||
|
||||
props: {
|
||||
lang: String,
|
||||
group: Object,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
active: [],
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
base() {
|
||||
return this.lang ? `/${this.lang}` : '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../common/style/var';
|
||||
|
||||
.demo-home-nav {
|
||||
&__title {
|
||||
margin: 24px 0 8px 16px;
|
||||
color: rgba(69, 90, 100, 0.6);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__block {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin: 0 0 12px;
|
||||
padding-left: 20px;
|
||||
color: #323233;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
background: #f7f8fa;
|
||||
border-radius: 99px;
|
||||
transition: background 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: darken(#f7f8fa, 3%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: darken(#f7f8fa, 6%);
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
58
vant/packages/vant-cli/site/mobile/components/DemoNav.vue
Normal file
58
vant/packages/vant-cli/site/mobile/components/DemoNav.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div v-show="title" class="demo-nav">
|
||||
<div class="demo-nav__title">{{ title }}</div>
|
||||
<svg class="demo-nav__back" viewBox="0 0 1000 1000" @click="onBack">
|
||||
<path fill="#969799" fill-rule="evenodd" :d="path" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable max-len */
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
path:
|
||||
'M296.114 508.035c-3.22-13.597.473-28.499 11.079-39.105l333.912-333.912c16.271-16.272 42.653-16.272 58.925 0s16.272 42.654 0 58.926L395.504 498.47l304.574 304.574c16.272 16.272 16.272 42.654 0 58.926s-42.654 16.272-58.926 0L307.241 528.058a41.472 41.472 0 0 1-11.127-20.023z',
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
title() {
|
||||
const { name } = this.$route.meta || {};
|
||||
return name ? name.replace(/-/g, '') : '';
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onBack() {
|
||||
history.back();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.demo-nav {
|
||||
position: relative;
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
|
||||
&__title {
|
||||
font-weight: 500;
|
||||
font-size: 17px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
&__back {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<section class="van-doc-demo-section" :class="demoName">
|
||||
<slot />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { decamelize } from '../../common';
|
||||
|
||||
export default {
|
||||
name: 'demo-section',
|
||||
|
||||
computed: {
|
||||
demoName() {
|
||||
const { meta } = this.$route || {};
|
||||
if (meta && meta.name) {
|
||||
return `demo-${decamelize(meta.name)}`;
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.van-doc-demo-section {
|
||||
box-sizing: border-box;
|
||||
min-height: calc(100vh - 56px);
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
41
vant/packages/vant-cli/site/mobile/index.html
Normal file
41
vant/packages/vant-cli/site/mobile/index.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<meta
|
||||
name="description"
|
||||
content="<%= htmlWebpackPlugin.options.description %>"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="<%= htmlWebpackPlugin.options.logo %>"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
|
||||
/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<% if (htmlWebpackPlugin.options.baiduAnalytics) { %>
|
||||
<script>
|
||||
// avoid to load analytics in iframe
|
||||
if (window.top === window) {
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement('script');
|
||||
hm.src =
|
||||
'https://hm.baidu.com/hm.js?<%= htmlWebpackPlugin.options.baiduAnalytics.seed %>';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
}
|
||||
</script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body ontouchstart>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
21
vant/packages/vant-cli/site/mobile/main.js
Normal file
21
vant/packages/vant-cli/site/mobile/main.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import Vue from 'vue';
|
||||
import DemoBlock from './components/DemoBlock';
|
||||
import DemoSection from './components/DemoSection';
|
||||
import { router } from './router';
|
||||
import App from './App';
|
||||
import '@vant/touch-emulator';
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Vue.config.productionTip = false;
|
||||
}
|
||||
|
||||
Vue.component(DemoBlock.name, DemoBlock);
|
||||
Vue.component(DemoSection.name, DemoSection);
|
||||
|
||||
setTimeout(() => {
|
||||
new Vue({
|
||||
el: '#app',
|
||||
render: h => h(App),
|
||||
router,
|
||||
});
|
||||
}, 0);
|
||||
98
vant/packages/vant-cli/site/mobile/router.js
Normal file
98
vant/packages/vant-cli/site/mobile/router.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import Vue from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import DemoHome from './components/DemoHome';
|
||||
import { decamelize } from '../common';
|
||||
import { demos, config } from 'site-mobile-shared';
|
||||
import { getLang, setDefaultLang } from '../common/locales';
|
||||
import '../common/iframe-router';
|
||||
|
||||
const { locales, defaultLang } = config.site;
|
||||
|
||||
setDefaultLang(defaultLang);
|
||||
|
||||
function getLangFromRoute(route) {
|
||||
const lang = route.path.split('/')[1];
|
||||
const langs = Object.keys(locales);
|
||||
|
||||
if (langs.indexOf(lang) !== -1) {
|
||||
return lang;
|
||||
}
|
||||
|
||||
return getLang();
|
||||
}
|
||||
|
||||
function getRoutes() {
|
||||
const routes = [];
|
||||
const names = Object.keys(demos);
|
||||
const langs = locales ? Object.keys(locales) : [];
|
||||
|
||||
if (langs.length) {
|
||||
routes.push({
|
||||
path: '*',
|
||||
redirect: route => `/${getLangFromRoute(route)}/`,
|
||||
});
|
||||
|
||||
langs.forEach(lang => {
|
||||
routes.push({
|
||||
path: `/${lang}`,
|
||||
component: DemoHome,
|
||||
meta: { lang },
|
||||
});
|
||||
});
|
||||
} else {
|
||||
routes.push({
|
||||
path: '*',
|
||||
redirect: () => '/',
|
||||
});
|
||||
|
||||
routes.push({
|
||||
path: '/',
|
||||
component: DemoHome,
|
||||
});
|
||||
}
|
||||
|
||||
names.forEach(name => {
|
||||
const component = decamelize(name);
|
||||
|
||||
if (langs.length) {
|
||||
langs.forEach(lang => {
|
||||
routes.push({
|
||||
name: `${lang}/${component}`,
|
||||
path: `/${lang}/${component}`,
|
||||
component: demos[name],
|
||||
meta: {
|
||||
name,
|
||||
lang,
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
routes.push({
|
||||
name,
|
||||
path: `/${component}`,
|
||||
component: demos[name],
|
||||
meta: {
|
||||
name,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
export const router = new VueRouter({
|
||||
mode: 'hash',
|
||||
routes: getRoutes(),
|
||||
scrollBehavior: (to, from, savedPosition) => savedPosition || { x: 0, y: 0 },
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
if (!router.currentRoute.redirectedFrom) {
|
||||
Vue.nextTick(window.syncPath);
|
||||
}
|
||||
});
|
||||
|
||||
window.vueRouter = router;
|
||||
1
vant/packages/vant-cli/src/.pydio
Normal file
1
vant/packages/vant-cli/src/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2aa2f818-dc71-47ba-aa93-7016eba90c51
|
||||
1
vant/packages/vant-cli/src/commands/.pydio
Normal file
1
vant/packages/vant-cli/src/commands/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
2bd2cf21-775d-4029-bbe9-fa816736f45c
|
||||
10
vant/packages/vant-cli/src/commands/build-site.ts
Normal file
10
vant/packages/vant-cli/src/commands/build-site.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { emptyDir } from 'fs-extra';
|
||||
import { setNodeEnv } from '../common';
|
||||
import { compileSite } from '../compiler/compile-site';
|
||||
import { SITE_DIST_DIR } from '../common/constant';
|
||||
|
||||
export async function buildSite() {
|
||||
setNodeEnv('production');
|
||||
await emptyDir(SITE_DIST_DIR);
|
||||
await compileSite(true);
|
||||
}
|
||||
197
vant/packages/vant-cli/src/commands/build.ts
Normal file
197
vant/packages/vant-cli/src/commands/build.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
import chokidar from 'chokidar';
|
||||
import { join, relative } from 'path';
|
||||
import { remove, copy, readdirSync } from 'fs-extra';
|
||||
import { clean } from './clean';
|
||||
import { CSS_LANG } from '../common/css';
|
||||
import { ora, consola, slimPath } from '../common/logger';
|
||||
import { installDependencies } from '../common/manager';
|
||||
import { compileJs } from '../compiler/compile-js';
|
||||
import { compileSfc } from '../compiler/compile-sfc';
|
||||
import { compileStyle } from '../compiler/compile-style';
|
||||
import { compilePackage } from '../compiler/compile-package';
|
||||
import { genPackageEntry } from '../compiler/gen-package-entry';
|
||||
import { genStyleDepsMap } from '../compiler/gen-style-deps-map';
|
||||
import { genComponentStyle } from '../compiler/gen-component-style';
|
||||
import { SRC_DIR, LIB_DIR, ES_DIR } from '../common/constant';
|
||||
import { genPacakgeStyle } from '../compiler/gen-package-style';
|
||||
import { genVeturConfig } from '../compiler/gen-vetur-config';
|
||||
import {
|
||||
isDir,
|
||||
isSfc,
|
||||
isStyle,
|
||||
isScript,
|
||||
isDemoDir,
|
||||
isTestDir,
|
||||
setNodeEnv,
|
||||
setModuleEnv,
|
||||
} from '../common';
|
||||
|
||||
async function compileFile(filePath: string) {
|
||||
if (isSfc(filePath)) {
|
||||
return compileSfc(filePath);
|
||||
}
|
||||
|
||||
if (isScript(filePath)) {
|
||||
return compileJs(filePath);
|
||||
}
|
||||
|
||||
if (isStyle(filePath)) {
|
||||
return compileStyle(filePath);
|
||||
}
|
||||
|
||||
return remove(filePath);
|
||||
}
|
||||
|
||||
async function compileDir(dir: string) {
|
||||
const files = readdirSync(dir);
|
||||
|
||||
await Promise.all(
|
||||
files.map(filename => {
|
||||
const filePath = join(dir, filename);
|
||||
|
||||
if (isDemoDir(filePath) || isTestDir(filePath)) {
|
||||
return remove(filePath);
|
||||
}
|
||||
|
||||
if (isDir(filePath)) {
|
||||
return compileDir(filePath);
|
||||
}
|
||||
|
||||
return compileFile(filePath);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async function buildEs() {
|
||||
setModuleEnv('esmodule');
|
||||
await copy(SRC_DIR, ES_DIR);
|
||||
await compileDir(ES_DIR);
|
||||
}
|
||||
|
||||
async function buildLib() {
|
||||
setModuleEnv('commonjs');
|
||||
await copy(SRC_DIR, LIB_DIR);
|
||||
await compileDir(LIB_DIR);
|
||||
}
|
||||
|
||||
async function buildStyleEntry() {
|
||||
await genStyleDepsMap();
|
||||
genComponentStyle();
|
||||
}
|
||||
|
||||
async function buildPacakgeEntry() {
|
||||
const esEntryFile = join(ES_DIR, 'index.js');
|
||||
const libEntryFile = join(LIB_DIR, 'index.js');
|
||||
const styleEntryFile = join(LIB_DIR, `index.${CSS_LANG}`);
|
||||
|
||||
genPackageEntry({
|
||||
outputPath: esEntryFile,
|
||||
pathResolver: (path: string) => `./${relative(SRC_DIR, path)}`,
|
||||
});
|
||||
|
||||
setModuleEnv('esmodule');
|
||||
await compileJs(esEntryFile);
|
||||
|
||||
genPacakgeStyle({
|
||||
outputPath: styleEntryFile,
|
||||
pathResolver: (path: string) => path.replace(SRC_DIR, '.'),
|
||||
});
|
||||
|
||||
setModuleEnv('commonjs');
|
||||
await copy(esEntryFile, libEntryFile);
|
||||
await compileJs(libEntryFile);
|
||||
await compileStyle(styleEntryFile);
|
||||
}
|
||||
|
||||
async function buildPackages() {
|
||||
setModuleEnv('esmodule');
|
||||
await compilePackage(false);
|
||||
await compilePackage(true);
|
||||
genVeturConfig();
|
||||
}
|
||||
|
||||
const tasks = [
|
||||
{
|
||||
text: 'Build ESModule Outputs',
|
||||
task: buildEs,
|
||||
},
|
||||
{
|
||||
text: 'Build Commonjs Outputs',
|
||||
task: buildLib,
|
||||
},
|
||||
{
|
||||
text: 'Build Style Entry',
|
||||
task: buildStyleEntry,
|
||||
},
|
||||
{
|
||||
text: 'Build Package Entry',
|
||||
task: buildPacakgeEntry,
|
||||
},
|
||||
{
|
||||
text: 'Build Packed Outputs',
|
||||
task: buildPackages,
|
||||
},
|
||||
];
|
||||
|
||||
async function runBuildTasks() {
|
||||
for (let i = 0; i < tasks.length; i++) {
|
||||
const { task, text } = tasks[i];
|
||||
const spinner = ora(text).start();
|
||||
|
||||
try {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
await task();
|
||||
spinner.succeed(text);
|
||||
} catch (err) {
|
||||
spinner.fail(text);
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
consola.success('Compile successfully');
|
||||
}
|
||||
|
||||
function watchFileChange() {
|
||||
consola.info('\nWatching file changes...');
|
||||
|
||||
chokidar.watch(SRC_DIR).on('change', async path => {
|
||||
if (isDemoDir(path) || isTestDir(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const spinner = ora('File changed, start compilation...').start();
|
||||
const esPath = path.replace(SRC_DIR, ES_DIR);
|
||||
const libPath = path.replace(SRC_DIR, LIB_DIR);
|
||||
|
||||
try {
|
||||
await copy(path, esPath);
|
||||
await copy(path, libPath);
|
||||
await compileFile(esPath);
|
||||
await compileFile(libPath);
|
||||
await genStyleDepsMap();
|
||||
genComponentStyle({ cache: false });
|
||||
spinner.succeed('Compiled: ' + slimPath(path));
|
||||
} catch (err) {
|
||||
spinner.fail('Compile failed: ' + path);
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function build(cmd: { watch?: boolean } = {}) {
|
||||
setNodeEnv('production');
|
||||
|
||||
try {
|
||||
await clean();
|
||||
await installDependencies();
|
||||
await runBuildTasks();
|
||||
|
||||
if (cmd.watch) {
|
||||
watchFileChange();
|
||||
}
|
||||
} catch (err) {
|
||||
consola.error('Build failed');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
73
vant/packages/vant-cli/src/commands/changelog.ts
Normal file
73
vant/packages/vant-cli/src/commands/changelog.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { join } from 'path';
|
||||
import { ROOT } from '../common/constant';
|
||||
import { ora, slimPath } from '../common/logger';
|
||||
import { createWriteStream, readFileSync } from 'fs-extra';
|
||||
// @ts-ignore
|
||||
import conventionalChangelog from 'conventional-changelog';
|
||||
|
||||
const DIST_FILE = join(ROOT, './changelog.generated.md');
|
||||
const MAIN_TEMPLATE = join(__dirname, '../../template/changelog-main.hbs');
|
||||
const HEADER_TEMPALTE = join(__dirname, '../../template/changelog-header.hbs');
|
||||
const COMMIT_TEMPALTE = join(__dirname, '../../template/changelog-commit.hbs');
|
||||
|
||||
const mainTemplate = readFileSync(MAIN_TEMPLATE, 'utf-8');
|
||||
const headerPartial = readFileSync(HEADER_TEMPALTE, 'utf-8');
|
||||
const commitPartial = readFileSync(COMMIT_TEMPALTE, 'utf-8');
|
||||
|
||||
function formatType(type: string) {
|
||||
const MAP: Record<string, string> = {
|
||||
fix: 'Bug Fixes',
|
||||
feat: 'Feature',
|
||||
docs: 'Document',
|
||||
types: 'Types',
|
||||
};
|
||||
|
||||
return MAP[type] || type;
|
||||
}
|
||||
|
||||
function transform(item: any) {
|
||||
if (item.type === 'chore' || item.type === 'test') {
|
||||
return null;
|
||||
}
|
||||
|
||||
item.type = formatType(item.type);
|
||||
|
||||
if (item.hash) {
|
||||
item.shortHash = item.hash.slice(0, 6);
|
||||
}
|
||||
|
||||
if (item.references.length) {
|
||||
item.references.forEach((ref: any) => {
|
||||
if (ref.issue) {
|
||||
item.subject = item.subject.replace(` (#${ref.issue})`, '');
|
||||
}
|
||||
});
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
export async function changelog(): Promise<void> {
|
||||
const spinner = ora('Generating changelog...').start();
|
||||
|
||||
return new Promise(resolve => {
|
||||
conventionalChangelog(
|
||||
{
|
||||
preset: 'angular',
|
||||
},
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
mainTemplate,
|
||||
headerPartial,
|
||||
commitPartial,
|
||||
transform,
|
||||
}
|
||||
)
|
||||
.pipe(createWriteStream(DIST_FILE))
|
||||
.on('close', () => {
|
||||
spinner.succeed(`Changelog generated at ${slimPath(DIST_FILE)}`);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
11
vant/packages/vant-cli/src/commands/clean.ts
Normal file
11
vant/packages/vant-cli/src/commands/clean.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { emptyDir } from 'fs-extra';
|
||||
import { ES_DIR, LIB_DIR, DIST_DIR, SITE_DIST_DIR } from '../common/constant';
|
||||
|
||||
export async function clean() {
|
||||
await Promise.all([
|
||||
emptyDir(ES_DIR),
|
||||
emptyDir(LIB_DIR),
|
||||
emptyDir(DIST_DIR),
|
||||
emptyDir(SITE_DIST_DIR),
|
||||
]);
|
||||
}
|
||||
38
vant/packages/vant-cli/src/commands/commit-lint.ts
Normal file
38
vant/packages/vant-cli/src/commands/commit-lint.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { readFileSync } from 'fs-extra';
|
||||
import { consola } from '../common/logger';
|
||||
|
||||
const commitRE = /^(revert: )?(fix|feat|docs|perf|test|types|build|chore|refactor|breaking change)(\(.+\))?: .{1,50}/;
|
||||
const mergeRE = /Merge branch /;
|
||||
|
||||
export function commitLint() {
|
||||
const gitParams = process.env.HUSKY_GIT_PARAMS as string;
|
||||
const commitMsg = readFileSync(gitParams, 'utf-8').trim();
|
||||
|
||||
if (!commitRE.test(commitMsg) && !mergeRE.test(commitMsg)) {
|
||||
consola.error(`invalid commit message: "${commitMsg}".
|
||||
|
||||
Proper commit message format is required for automated changelog generation.
|
||||
|
||||
Examples:
|
||||
|
||||
- fix(Button): incorrect style
|
||||
- feat(Button): incorrect style
|
||||
- docs(Button): fix typo
|
||||
|
||||
Allowed Types:
|
||||
|
||||
- fix
|
||||
- feat
|
||||
- docs
|
||||
- perf
|
||||
- test
|
||||
- types
|
||||
- build
|
||||
- chore
|
||||
- refactor
|
||||
- breaking change
|
||||
- Merge branch 'foo' into 'bar'
|
||||
`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
7
vant/packages/vant-cli/src/commands/dev.ts
Normal file
7
vant/packages/vant-cli/src/commands/dev.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { setNodeEnv } from '../common';
|
||||
import { compileSite } from '../compiler/compile-site';
|
||||
|
||||
export async function dev() {
|
||||
setNodeEnv('development');
|
||||
await compileSite();
|
||||
}
|
||||
33
vant/packages/vant-cli/src/commands/jest.ts
Normal file
33
vant/packages/vant-cli/src/commands/jest.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { runCLI } from 'jest';
|
||||
import { setNodeEnv } from '../common';
|
||||
import { genPackageEntry } from '../compiler/gen-package-entry';
|
||||
import { ROOT, JEST_CONFIG_FILE, PACKAGE_ENTRY_FILE } from '../common/constant';
|
||||
|
||||
export function test(command: any) {
|
||||
setNodeEnv('test');
|
||||
|
||||
genPackageEntry({
|
||||
outputPath: PACKAGE_ENTRY_FILE,
|
||||
});
|
||||
|
||||
const config = {
|
||||
rootDir: ROOT,
|
||||
watch: command.watch,
|
||||
config: JEST_CONFIG_FILE,
|
||||
clearCache: command.clearCache,
|
||||
} as any;
|
||||
|
||||
runCLI(config, [ROOT])
|
||||
.then(response => {
|
||||
if (!response.results.success && !command.watch) {
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
|
||||
if (!command.watch) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
66
vant/packages/vant-cli/src/commands/lint.ts
Normal file
66
vant/packages/vant-cli/src/commands/lint.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
// @ts-ignore
|
||||
import execa from 'execa';
|
||||
import { ora } from '../common/logger';
|
||||
import { SCRIPT_EXTS } from '../common/constant';
|
||||
|
||||
type RunCommandMessages = {
|
||||
start: string;
|
||||
succeed: string;
|
||||
failed: string;
|
||||
};
|
||||
|
||||
function runCommand(
|
||||
cmd: string,
|
||||
options: string[],
|
||||
messages: RunCommandMessages
|
||||
) {
|
||||
const spinner = ora(messages.start).start();
|
||||
|
||||
return new Promise(resolve => {
|
||||
execa(cmd, options, {
|
||||
env: { FORCE_COLOR: true },
|
||||
})
|
||||
.then(() => {
|
||||
spinner.succeed(messages.succeed);
|
||||
resolve(true);
|
||||
})
|
||||
.catch((err: any) => {
|
||||
spinner.fail(messages.failed);
|
||||
console.log(err.stdout);
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function eslint() {
|
||||
return runCommand(
|
||||
'eslint',
|
||||
['./src', '--fix', '--ext', SCRIPT_EXTS.join(',')],
|
||||
{
|
||||
start: 'Running eslint...',
|
||||
succeed: 'ESLint Passed.',
|
||||
failed: 'ESLint failed!',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function stylelint() {
|
||||
return runCommand(
|
||||
'stylelint',
|
||||
['src/**/*.css', 'src/**/*.vue', 'src/**/*.less', 'src/**/*.sass', '--fix'],
|
||||
{
|
||||
start: 'Running stylelint...',
|
||||
succeed: 'Stylelint Passed.',
|
||||
failed: 'Stylelint failed!',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function lint() {
|
||||
const eslintPassed = await eslint();
|
||||
const stylelintPassed = await stylelint();
|
||||
|
||||
if (!eslintPassed || !stylelintPassed) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
18
vant/packages/vant-cli/src/commands/release.ts
Normal file
18
vant/packages/vant-cli/src/commands/release.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
// @ts-ignore
|
||||
import releaseIt from 'release-it';
|
||||
import { join } from 'path';
|
||||
|
||||
const PLUGIN_PATH = join(__dirname, '../compiler/vant-cli-release-plugin.js');
|
||||
|
||||
export async function release() {
|
||||
await releaseIt({
|
||||
plugins: {
|
||||
[PLUGIN_PATH]: {},
|
||||
},
|
||||
git: {
|
||||
tagName: 'v${version}',
|
||||
commitMessage: 'chore: release ${version}',
|
||||
},
|
||||
});
|
||||
}
|
||||
1
vant/packages/vant-cli/src/common/.pydio
Normal file
1
vant/packages/vant-cli/src/common/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
42ce7cd3-d672-420d-83d0-26a678e831c6
|
||||
91
vant/packages/vant-cli/src/common/constant.ts
Normal file
91
vant/packages/vant-cli/src/common/constant.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { get } from 'lodash';
|
||||
import { existsSync } from 'fs-extra';
|
||||
import { join, dirname, isAbsolute } from 'path';
|
||||
|
||||
function findRootDir(dir: string): string {
|
||||
if (dir === '/') {
|
||||
return '/';
|
||||
}
|
||||
|
||||
if (existsSync(join(dir, 'vant.config.js'))) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
return findRootDir(dirname(dir));
|
||||
}
|
||||
|
||||
// Colors
|
||||
export const GREEN = '#07c160';
|
||||
|
||||
// Root paths
|
||||
export const CWD = process.cwd();
|
||||
export const ROOT = findRootDir(CWD);
|
||||
export const ES_DIR = join(ROOT, 'es');
|
||||
export const LIB_DIR = join(ROOT, 'lib');
|
||||
export const DOCS_DIR = join(ROOT, 'docs');
|
||||
export const SITE_DIST_DIR = join(ROOT, 'site');
|
||||
export const VANT_CONFIG_FILE = join(ROOT, 'vant.config.js');
|
||||
export const PACKAGE_JSON_FILE = join(ROOT, 'package.json');
|
||||
export const ROOT_WEBPACK_CONFIG_FILE = join(ROOT, 'webpack.config.js');
|
||||
export const ROOT_POSTCSS_CONFIG_FILE = join(ROOT, 'postcss.config.js');
|
||||
export const CACHE_DIR = join(ROOT, 'node_modules/.cache');
|
||||
|
||||
// Relative paths
|
||||
export const DIST_DIR = join(__dirname, '../../dist');
|
||||
export const CONFIG_DIR = join(__dirname, '../config');
|
||||
|
||||
// Dist files
|
||||
export const PACKAGE_ENTRY_FILE = join(DIST_DIR, 'package-entry.js');
|
||||
export const PACKAGE_STYLE_FILE = join(DIST_DIR, 'package-style.css');
|
||||
export const SITE_MODILE_SHARED_FILE = join(DIST_DIR, 'site-mobile-shared.js');
|
||||
export const SITE_DESKTOP_SHARED_FILE = join(
|
||||
DIST_DIR,
|
||||
'site-desktop-shared.js'
|
||||
);
|
||||
export const STYPE_DEPS_JSON_FILE = join(DIST_DIR, 'style-deps.json');
|
||||
|
||||
// Config files
|
||||
export const BABEL_CONFIG_FILE = join(CONFIG_DIR, 'babel.config.js');
|
||||
export const POSTCSS_CONFIG_FILE = join(CONFIG_DIR, 'postcss.config.js');
|
||||
export const JEST_SETUP_FILE = join(CONFIG_DIR, 'jest.setup.js');
|
||||
export const JEST_CONFIG_FILE = join(CONFIG_DIR, 'jest.config.js');
|
||||
export const JEST_TRANSFORM_FILE = join(CONFIG_DIR, 'jest.transform.js');
|
||||
export const JEST_FILE_MOCK_FILE = join(CONFIG_DIR, 'jest.file-mock.js');
|
||||
export const JEST_STYLE_MOCK_FILE = join(CONFIG_DIR, 'jest.style-mock.js');
|
||||
|
||||
export const SCRIPT_EXTS = ['.js', '.jsx', '.vue', '.ts', '.tsx'];
|
||||
export const STYLE_EXTS = ['.css', '.less', '.scss'];
|
||||
|
||||
export function getPackageJson() {
|
||||
delete require.cache[PACKAGE_JSON_FILE];
|
||||
|
||||
return require(PACKAGE_JSON_FILE);
|
||||
}
|
||||
|
||||
export function getVantConfig() {
|
||||
delete require.cache[VANT_CONFIG_FILE];
|
||||
|
||||
try {
|
||||
return require(VANT_CONFIG_FILE);
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function getSrcDir() {
|
||||
const vantConfig = getVantConfig();
|
||||
const srcDir = get(vantConfig, 'build.srcDir');
|
||||
|
||||
if (srcDir) {
|
||||
if (isAbsolute(srcDir)) {
|
||||
return srcDir;
|
||||
}
|
||||
|
||||
return join(ROOT, srcDir);
|
||||
}
|
||||
|
||||
return join(ROOT, 'src');
|
||||
}
|
||||
|
||||
export const SRC_DIR = getSrcDir();
|
||||
export const STYLE_DIR = join(SRC_DIR, 'style');
|
||||
45
vant/packages/vant-cli/src/common/css.ts
Normal file
45
vant/packages/vant-cli/src/common/css.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { get } from 'lodash';
|
||||
import { existsSync } from 'fs';
|
||||
import { join, isAbsolute } from 'path';
|
||||
import { getVantConfig } from '../common';
|
||||
import { STYLE_DIR, SRC_DIR } from './constant';
|
||||
|
||||
type CSS_LANG = 'css' | 'less' | 'scss';
|
||||
|
||||
function getCssLang(): CSS_LANG {
|
||||
const vantConfig = getVantConfig();
|
||||
const preprocessor = get(vantConfig, 'build.css.preprocessor', 'less');
|
||||
|
||||
if (preprocessor === 'sass') {
|
||||
return 'scss';
|
||||
}
|
||||
|
||||
return preprocessor;
|
||||
}
|
||||
|
||||
export const CSS_LANG = getCssLang();
|
||||
|
||||
export function getCssBaseFile() {
|
||||
const vantConfig = getVantConfig();
|
||||
let path = join(STYLE_DIR, `base.${CSS_LANG}`);
|
||||
|
||||
const baseFile = get(vantConfig, 'build.css.base', '');
|
||||
if (baseFile) {
|
||||
path = isAbsolute(baseFile) ? baseFile : join(SRC_DIR, baseFile);
|
||||
}
|
||||
|
||||
if (existsSync(path)) {
|
||||
return path;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const IMPORT_STYLE_RE = /import\s+?(?:(?:".*?")|(?:'.*?'))[\s]*?(?:;|$|)/g;
|
||||
|
||||
// "import 'a.less';" => "import 'a.css';"
|
||||
export function replaceCssImport(code: string) {
|
||||
return code.replace(IMPORT_STYLE_RE, str =>
|
||||
str.replace(`.${CSS_LANG}`, '.css')
|
||||
);
|
||||
}
|
||||
158
vant/packages/vant-cli/src/common/index.ts
Normal file
158
vant/packages/vant-cli/src/common/index.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import { join } from 'path';
|
||||
import {
|
||||
lstatSync,
|
||||
existsSync,
|
||||
readdirSync,
|
||||
readFileSync,
|
||||
outputFileSync,
|
||||
} from 'fs-extra';
|
||||
import {
|
||||
SRC_DIR,
|
||||
getVantConfig,
|
||||
ROOT_WEBPACK_CONFIG_FILE,
|
||||
ROOT_POSTCSS_CONFIG_FILE,
|
||||
} from './constant';
|
||||
|
||||
export const EXT_REGEXP = /\.\w+$/;
|
||||
export const SFC_REGEXP = /\.(vue)$/;
|
||||
export const DEMO_REGEXP = /\/demo$/;
|
||||
export const TEST_REGEXP = /\/test$/;
|
||||
export const STYLE_REGEXP = /\.(css|less|scss)$/;
|
||||
export const SCRIPT_REGEXP = /\.(js|ts|jsx|tsx)$/;
|
||||
export const ENTRY_EXTS = ['js', 'ts', 'tsx', 'jsx', 'vue'];
|
||||
|
||||
export function removeExt(path: string) {
|
||||
return path.replace('.js', '');
|
||||
}
|
||||
|
||||
export function replaceExt(path: string, ext: string) {
|
||||
return path.replace(EXT_REGEXP, ext);
|
||||
}
|
||||
|
||||
export function hasDefaultExport(code: string) {
|
||||
return code.includes('export default') || code.includes('export { default }');
|
||||
}
|
||||
|
||||
export function getComponents() {
|
||||
const EXCLUDES = ['.DS_Store'];
|
||||
const dirs = readdirSync(SRC_DIR);
|
||||
return dirs
|
||||
.filter(dir => !EXCLUDES.includes(dir))
|
||||
.filter(dir =>
|
||||
ENTRY_EXTS.some(ext => {
|
||||
const path = join(SRC_DIR, dir, `index.${ext}`);
|
||||
if (existsSync(path)) {
|
||||
return hasDefaultExport(readFileSync(path, 'utf-8'));
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function isDir(dir: string) {
|
||||
return lstatSync(dir).isDirectory();
|
||||
}
|
||||
|
||||
export function isDemoDir(dir: string) {
|
||||
return DEMO_REGEXP.test(dir);
|
||||
}
|
||||
|
||||
export function isTestDir(dir: string) {
|
||||
return TEST_REGEXP.test(dir);
|
||||
}
|
||||
|
||||
export function isSfc(path: string) {
|
||||
return SFC_REGEXP.test(path);
|
||||
}
|
||||
|
||||
export function isStyle(path: string) {
|
||||
return STYLE_REGEXP.test(path);
|
||||
}
|
||||
|
||||
export function isScript(path: string) {
|
||||
return SCRIPT_REGEXP.test(path);
|
||||
}
|
||||
|
||||
const camelizeRE = /-(\w)/g;
|
||||
const pascalizeRE = /(\w)(\w*)/g;
|
||||
|
||||
export function camelize(str: string): string {
|
||||
return str.replace(camelizeRE, (_, c) => c.toUpperCase());
|
||||
}
|
||||
|
||||
export function pascalize(str: string): string {
|
||||
return camelize(str).replace(
|
||||
pascalizeRE,
|
||||
(_, c1, c2) => c1.toUpperCase() + c2
|
||||
);
|
||||
}
|
||||
|
||||
export function decamelize(str: string, sep = '-') {
|
||||
return str
|
||||
.replace(/([a-z\d])([A-Z])/g, '$1' + sep + '$2')
|
||||
.replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + sep + '$2')
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export function normalizePath(path: string): string {
|
||||
return path.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
export function getWebpackConfig(): object {
|
||||
if (existsSync(ROOT_WEBPACK_CONFIG_FILE)) {
|
||||
const config = require(ROOT_WEBPACK_CONFIG_FILE);
|
||||
|
||||
if (typeof config === 'function') {
|
||||
return config();
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
export function getPostcssConfig(): object {
|
||||
if (existsSync(ROOT_POSTCSS_CONFIG_FILE)) {
|
||||
return require(ROOT_POSTCSS_CONFIG_FILE);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
export type ModuleEnv = 'esmodule' | 'commonjs';
|
||||
export type NodeEnv = 'production' | 'development' | 'test';
|
||||
export type BuildTarget = 'site' | 'package';
|
||||
|
||||
export function setModuleEnv(value: ModuleEnv) {
|
||||
process.env.BABEL_MODULE = value;
|
||||
}
|
||||
|
||||
export function setNodeEnv(value: NodeEnv) {
|
||||
process.env.NODE_ENV = value;
|
||||
}
|
||||
|
||||
export function setBuildTarget(value: BuildTarget) {
|
||||
process.env.BUILD_TARGET = value;
|
||||
}
|
||||
|
||||
export function isDev() {
|
||||
return process.env.NODE_ENV === 'development';
|
||||
}
|
||||
|
||||
// smarter outputFileSync
|
||||
// skip output if file content unchanged
|
||||
export function smartOutputFile(filePath: string, content: string) {
|
||||
if (existsSync(filePath)) {
|
||||
const previousContent = readFileSync(filePath, 'utf-8');
|
||||
|
||||
if (previousContent === content) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
outputFileSync(filePath, content);
|
||||
}
|
||||
|
||||
export { getVantConfig };
|
||||
10
vant/packages/vant-cli/src/common/logger.ts
Normal file
10
vant/packages/vant-cli/src/common/logger.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import ora from 'ora';
|
||||
import chalk from 'chalk';
|
||||
import consola from 'consola';
|
||||
import { ROOT } from '../common/constant';
|
||||
|
||||
export function slimPath(path: string) {
|
||||
return chalk.yellow(path.replace(ROOT, ''));
|
||||
}
|
||||
|
||||
export { ora, consola };
|
||||
36
vant/packages/vant-cli/src/common/manager.ts
Normal file
36
vant/packages/vant-cli/src/common/manager.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
// @ts-ignore
|
||||
import execa from 'execa';
|
||||
import { consola } from './logger';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
let hasYarnCache: boolean;
|
||||
|
||||
export function hasYarn() {
|
||||
if (hasYarnCache === undefined) {
|
||||
try {
|
||||
execSync('yarn --version', { stdio: 'ignore' });
|
||||
hasYarnCache = true;
|
||||
} catch (e) {
|
||||
hasYarnCache = false;
|
||||
}
|
||||
}
|
||||
|
||||
return hasYarnCache;
|
||||
}
|
||||
|
||||
export async function installDependencies() {
|
||||
consola.info('Install Dependencies\n');
|
||||
|
||||
try {
|
||||
const manager = hasYarn() ? 'yarn' : 'npm';
|
||||
|
||||
await execa(manager, ['install', '--prod=false'], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
console.log('');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
1
vant/packages/vant-cli/src/compiler/.pydio
Normal file
1
vant/packages/vant-cli/src/compiler/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
3abfeb71-09b9-4b01-aedc-247e9e6ea32e
|
||||
15
vant/packages/vant-cli/src/compiler/compile-css.ts
Normal file
15
vant/packages/vant-cli/src/compiler/compile-css.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import postcss from 'postcss';
|
||||
import postcssrc from 'postcss-load-config';
|
||||
import CleanCss from 'clean-css';
|
||||
import { POSTCSS_CONFIG_FILE } from '../common/constant';
|
||||
|
||||
const cleanCss = new CleanCss();
|
||||
|
||||
export async function compileCss(source: string | Buffer) {
|
||||
const config = await postcssrc({}, POSTCSS_CONFIG_FILE);
|
||||
const { css } = await postcss(config.plugins as any).process(source, {
|
||||
from: undefined,
|
||||
});
|
||||
|
||||
return cleanCss.minify(css).styles;
|
||||
}
|
||||
24
vant/packages/vant-cli/src/compiler/compile-js.ts
Normal file
24
vant/packages/vant-cli/src/compiler/compile-js.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { transformAsync } from '@babel/core';
|
||||
import { readFileSync, removeSync, outputFileSync } from 'fs-extra';
|
||||
import { replaceExt } from '../common';
|
||||
import { replaceCssImport } from '../common/css';
|
||||
|
||||
export function compileJs(filePath: string): Promise<undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let code = readFileSync(filePath, 'utf-8');
|
||||
|
||||
code = replaceCssImport(code);
|
||||
|
||||
transformAsync(code, { filename: filePath })
|
||||
.then(result => {
|
||||
if (result) {
|
||||
const jsFilePath = replaceExt(filePath, '.js');
|
||||
|
||||
removeSync(filePath);
|
||||
outputFileSync(jsFilePath, result.code);
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
27
vant/packages/vant-cli/src/compiler/compile-less.ts
Normal file
27
vant/packages/vant-cli/src/compiler/compile-less.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// @ts-ignore
|
||||
import { render, FileManager } from 'less';
|
||||
import { readFileSync } from 'fs-extra';
|
||||
|
||||
// less plugin to resolve tilde
|
||||
class TildeResolver extends FileManager {
|
||||
loadFile(filename: string, ...args: any[]) {
|
||||
filename = filename.replace('~', '');
|
||||
return FileManager.prototype.loadFile.apply(this, [filename, ...args]);
|
||||
}
|
||||
}
|
||||
|
||||
const TildeResolverPlugin = {
|
||||
install(lessInstance: unknown, pluginManager: any) {
|
||||
pluginManager.addFileManager(new TildeResolver());
|
||||
},
|
||||
};
|
||||
|
||||
export async function compileLess(filePath: string) {
|
||||
const source = readFileSync(filePath, 'utf-8');
|
||||
const { css } = await render(source, {
|
||||
filename: filePath,
|
||||
plugins: [TildeResolverPlugin],
|
||||
});
|
||||
|
||||
return css;
|
||||
}
|
||||
16
vant/packages/vant-cli/src/compiler/compile-package.ts
Normal file
16
vant/packages/vant-cli/src/compiler/compile-package.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import webpack from 'webpack';
|
||||
import { getPackageConfig } from '../config/webpack.package';
|
||||
|
||||
export async function compilePackage(isMinify: boolean) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const config = getPackageConfig(isMinify);
|
||||
|
||||
webpack(config, (err, stats) => {
|
||||
if (err || stats.hasErrors()) {
|
||||
reject();
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
6
vant/packages/vant-cli/src/compiler/compile-sass.ts
Normal file
6
vant/packages/vant-cli/src/compiler/compile-sass.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { renderSync } from 'sass';
|
||||
|
||||
export async function compileSass(filePath: string) {
|
||||
const { css } = renderSync({ file: filePath });
|
||||
return css;
|
||||
}
|
||||
129
vant/packages/vant-cli/src/compiler/compile-sfc.ts
Normal file
129
vant/packages/vant-cli/src/compiler/compile-sfc.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import * as compiler from 'vue-template-compiler';
|
||||
import * as compileUtils from '@vue/component-compiler-utils';
|
||||
import { parse } from 'path';
|
||||
import { remove, writeFileSync, readFileSync } from 'fs-extra';
|
||||
import { replaceExt } from '../common';
|
||||
import { compileJs } from './compile-js';
|
||||
import { compileStyle } from './compile-style';
|
||||
|
||||
const RENDER_FN = '__vue_render__';
|
||||
const STATIC_RENDER_FN = '__vue_staticRenderFns__';
|
||||
const EXPORT = 'export default {';
|
||||
|
||||
// trim some unused code
|
||||
function trim(code: string) {
|
||||
return code.replace(/\/\/\n/g, '').trim();
|
||||
}
|
||||
|
||||
function getSfcStylePath(filePath: string, ext: string, index: number) {
|
||||
const number = index !== 0 ? `-${index + 1}` : '';
|
||||
return replaceExt(filePath, `-sfc${number}.${ext}`);
|
||||
}
|
||||
|
||||
// inject render fn to script
|
||||
function injectRender(script: string, render: string) {
|
||||
script = trim(script);
|
||||
|
||||
render = render
|
||||
.replace('var render', `var ${RENDER_FN}`)
|
||||
.replace('var staticRenderFns', `var ${STATIC_RENDER_FN}`);
|
||||
|
||||
return script.replace(
|
||||
EXPORT,
|
||||
`${render}\n${EXPORT}\n render: ${RENDER_FN},\n\n staticRenderFns: ${STATIC_RENDER_FN},\n`
|
||||
);
|
||||
}
|
||||
|
||||
function injectStyle(
|
||||
script: string,
|
||||
styles: compileUtils.SFCBlock[],
|
||||
filePath: string
|
||||
) {
|
||||
if (styles.length) {
|
||||
const imports = styles
|
||||
.map((style, index) => {
|
||||
const { base } = parse(getSfcStylePath(filePath, 'css', index));
|
||||
return `import './${base}';`;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return script.replace(EXPORT, `${imports}\n\n${EXPORT}`);
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
function compileTemplate(template: string) {
|
||||
const result = compileUtils.compileTemplate({
|
||||
compiler,
|
||||
source: template,
|
||||
isProduction: true,
|
||||
} as any);
|
||||
|
||||
return result.code;
|
||||
}
|
||||
|
||||
type CompileSfcOptions = {
|
||||
skipStyle?: boolean;
|
||||
};
|
||||
|
||||
export function parseSfc(filePath: string) {
|
||||
const source = readFileSync(filePath, 'utf-8');
|
||||
|
||||
const descriptor = compileUtils.parse({
|
||||
source,
|
||||
compiler,
|
||||
needMap: false,
|
||||
} as any);
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
export async function compileSfc(
|
||||
filePath: string,
|
||||
options: CompileSfcOptions = {}
|
||||
): Promise<any> {
|
||||
const tasks = [remove(filePath)];
|
||||
const jsFilePath = replaceExt(filePath, '.js');
|
||||
const descriptor = parseSfc(filePath);
|
||||
const { template, styles } = descriptor;
|
||||
|
||||
// compile js part
|
||||
if (descriptor.script) {
|
||||
tasks.push(
|
||||
new Promise((resolve, reject) => {
|
||||
let script = descriptor.script!.content;
|
||||
script = injectStyle(script, styles, filePath);
|
||||
|
||||
if (template) {
|
||||
const render = compileTemplate(template.content);
|
||||
script = injectRender(script, render);
|
||||
}
|
||||
|
||||
writeFileSync(jsFilePath, script);
|
||||
compileJs(jsFilePath)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// compile style part
|
||||
if (!options.skipStyle) {
|
||||
tasks.push(
|
||||
...styles.map((style, index: number) => {
|
||||
const cssFilePath = getSfcStylePath(
|
||||
filePath,
|
||||
style.lang || 'css',
|
||||
index
|
||||
);
|
||||
|
||||
writeFileSync(cssFilePath, trim(style.content));
|
||||
|
||||
return compileStyle(cssFilePath);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.all(tasks);
|
||||
}
|
||||
76
vant/packages/vant-cli/src/compiler/compile-site.ts
Normal file
76
vant/packages/vant-cli/src/compiler/compile-site.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import chalk from 'chalk';
|
||||
import address from 'address';
|
||||
import webpack from 'webpack';
|
||||
import WebpackDevServer from 'webpack-dev-server';
|
||||
import { get } from 'lodash';
|
||||
import { getPort } from 'portfinder';
|
||||
import { GREEN } from '../common/constant';
|
||||
import { getSiteDevConfig } from '../config/webpack.site.dev';
|
||||
import { getSitePrdConfig } from '../config/webpack.site.prd';
|
||||
|
||||
function logServerInfo(port: number) {
|
||||
const local = `http://localhost:${port}/`;
|
||||
const network = `http://${address.ip()}:${port}/`;
|
||||
|
||||
console.log('\n Site running at:\n');
|
||||
console.log(` ${chalk.bold('Local')}: ${chalk.hex(GREEN)(local)} `);
|
||||
console.log(` ${chalk.bold('Network')}: ${chalk.hex(GREEN)(network)}`);
|
||||
}
|
||||
|
||||
function runDevServer(
|
||||
port: number,
|
||||
config: ReturnType<typeof getSiteDevConfig>
|
||||
) {
|
||||
const server = new WebpackDevServer(webpack(config), config.devServer);
|
||||
|
||||
// this is a hack to disable wds status log
|
||||
(server as any).showStatus = function() {};
|
||||
|
||||
const host = get(config.devServer, 'host', 'localhost');
|
||||
server.listen(port, host, (err?: Error) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function watch() {
|
||||
const config = getSiteDevConfig();
|
||||
|
||||
getPort(
|
||||
{
|
||||
port: config.devServer!.port,
|
||||
},
|
||||
(err, port) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
logServerInfo(port);
|
||||
runDevServer(port, config);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function build() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const config = getSitePrdConfig();
|
||||
|
||||
webpack(config, (err, stats) => {
|
||||
if (err || stats.hasErrors()) {
|
||||
reject();
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function compileSite(production = false) {
|
||||
if (production) {
|
||||
await build();
|
||||
} else {
|
||||
watch();
|
||||
}
|
||||
}
|
||||
35
vant/packages/vant-cli/src/compiler/compile-style.ts
Normal file
35
vant/packages/vant-cli/src/compiler/compile-style.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { parse } from 'path';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { replaceExt } from '../common';
|
||||
import { compileCss } from './compile-css';
|
||||
import { compileLess } from './compile-less';
|
||||
import { compileSass } from './compile-sass';
|
||||
import { consola } from '../common/logger';
|
||||
|
||||
async function compileFile(filePath: string) {
|
||||
const parsedPath = parse(filePath);
|
||||
|
||||
try {
|
||||
if (parsedPath.ext === '.less') {
|
||||
const source = await compileLess(filePath);
|
||||
return await compileCss(source);
|
||||
}
|
||||
|
||||
if (parsedPath.ext === '.scss') {
|
||||
const source = await compileSass(filePath);
|
||||
return await compileCss(source);
|
||||
}
|
||||
|
||||
const source = readFileSync(filePath, 'utf-8');
|
||||
return await compileCss(source);
|
||||
} catch (err) {
|
||||
consola.error('Compile style failed: ' + filePath);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export async function compileStyle(filePath: string) {
|
||||
const css = await compileFile(filePath);
|
||||
|
||||
writeFileSync(replaceExt(filePath, '.css'), css);
|
||||
}
|
||||
107
vant/packages/vant-cli/src/compiler/gen-component-style.ts
Normal file
107
vant/packages/vant-cli/src/compiler/gen-component-style.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Build style entry of all components
|
||||
*/
|
||||
|
||||
import { join, relative } from 'path';
|
||||
import { outputFileSync } from 'fs-extra';
|
||||
import { getComponents, replaceExt } from '../common';
|
||||
import { CSS_LANG, getCssBaseFile } from '../common/css';
|
||||
import { checkStyleExists } from './gen-style-deps-map';
|
||||
import {
|
||||
ES_DIR,
|
||||
SRC_DIR,
|
||||
LIB_DIR,
|
||||
STYPE_DEPS_JSON_FILE,
|
||||
} from '../common/constant';
|
||||
|
||||
function getDeps(component: string): string[] {
|
||||
const styleDepsJson = require(STYPE_DEPS_JSON_FILE);
|
||||
|
||||
if (styleDepsJson.map[component]) {
|
||||
const deps = styleDepsJson.map[component].slice(0);
|
||||
|
||||
if (checkStyleExists(component)) {
|
||||
deps.push(component);
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function getPath(component: string, ext = '.css') {
|
||||
return join(ES_DIR, `${component}/index${ext}`);
|
||||
}
|
||||
|
||||
function getRelativePath(component: string, style: string, ext: string) {
|
||||
return relative(join(ES_DIR, `${component}/style`), getPath(style, ext));
|
||||
}
|
||||
|
||||
const OUTPUT_CONFIG = [
|
||||
{
|
||||
dir: ES_DIR,
|
||||
template: (dep: string) => `import '${dep}';`,
|
||||
},
|
||||
{
|
||||
dir: LIB_DIR,
|
||||
template: (dep: string) => `require('${dep}');`,
|
||||
},
|
||||
];
|
||||
|
||||
function genEntry(params: {
|
||||
ext: string;
|
||||
filename: string;
|
||||
component: string;
|
||||
baseFile: string | null;
|
||||
}) {
|
||||
const { ext, filename, component, baseFile } = params;
|
||||
const deps = getDeps(component);
|
||||
const depsPath = deps.map(dep => getRelativePath(component, dep, ext));
|
||||
|
||||
OUTPUT_CONFIG.forEach(({ dir, template }) => {
|
||||
const outputDir = join(dir, component, 'style');
|
||||
const outputFile = join(outputDir, filename);
|
||||
|
||||
let content = '';
|
||||
|
||||
if (baseFile) {
|
||||
const compiledBaseFile = replaceExt(baseFile.replace(SRC_DIR, dir), ext);
|
||||
content += template(relative(outputDir, compiledBaseFile));
|
||||
content += '\n';
|
||||
}
|
||||
|
||||
content += depsPath.map(template).join('\n');
|
||||
|
||||
outputFileSync(outputFile, content);
|
||||
});
|
||||
}
|
||||
|
||||
export function genComponentStyle(
|
||||
options: { cache: boolean } = { cache: true }
|
||||
) {
|
||||
if (!options.cache) {
|
||||
delete require.cache[STYPE_DEPS_JSON_FILE];
|
||||
}
|
||||
|
||||
const components = getComponents();
|
||||
const baseFile = getCssBaseFile();
|
||||
|
||||
components.forEach(component => {
|
||||
genEntry({
|
||||
baseFile,
|
||||
component,
|
||||
filename: 'index.js',
|
||||
ext: '.css',
|
||||
});
|
||||
|
||||
if (CSS_LANG !== 'css') {
|
||||
genEntry({
|
||||
baseFile,
|
||||
component,
|
||||
filename: CSS_LANG + '.js',
|
||||
ext: '.' + CSS_LANG,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
75
vant/packages/vant-cli/src/compiler/gen-package-entry.ts
Normal file
75
vant/packages/vant-cli/src/compiler/gen-package-entry.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { get } from 'lodash';
|
||||
import { join } from 'path';
|
||||
import {
|
||||
pascalize,
|
||||
getComponents,
|
||||
smartOutputFile,
|
||||
normalizePath,
|
||||
} from '../common';
|
||||
import { SRC_DIR, getPackageJson, getVantConfig } from '../common/constant';
|
||||
|
||||
type Options = {
|
||||
outputPath: string;
|
||||
pathResolver?: Function;
|
||||
};
|
||||
|
||||
function genImports(components: string[], options: Options): string {
|
||||
return components
|
||||
.map(name => {
|
||||
let path = join(SRC_DIR, name);
|
||||
if (options.pathResolver) {
|
||||
path = options.pathResolver(path);
|
||||
}
|
||||
|
||||
return `import ${pascalize(name)} from '${normalizePath(path)}';`;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function genExports(names: string[]): string {
|
||||
return names.map(name => `${name}`).join(',\n ');
|
||||
}
|
||||
|
||||
export function genPackageEntry(options: Options) {
|
||||
const names = getComponents();
|
||||
const vantConfig = getVantConfig();
|
||||
const skipInstall = get(vantConfig, 'build.skipInstall', []).map(pascalize);
|
||||
const version = process.env.PACKAGE_VERSION || getPackageJson().version;
|
||||
|
||||
const components = names.map(pascalize);
|
||||
const content = `${genImports(names, options)}
|
||||
|
||||
const version = '${version}';
|
||||
|
||||
function install(Vue) {
|
||||
const components = [
|
||||
${components.filter(item => !skipInstall.includes(item)).join(',\n ')}
|
||||
];
|
||||
|
||||
components.forEach(item => {
|
||||
if (item.install) {
|
||||
Vue.use(item);
|
||||
} else if (item.name) {
|
||||
Vue.component(item.name, item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
install(window.Vue);
|
||||
}
|
||||
|
||||
export {
|
||||
install,
|
||||
version,
|
||||
${genExports(components)}
|
||||
};
|
||||
|
||||
export default {
|
||||
install,
|
||||
version
|
||||
};
|
||||
`;
|
||||
|
||||
smartOutputFile(options.outputPath, content);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user