first commit
This commit is contained in:
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
326
README.md
Normal file
326
README.md
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
## vue-cli-plugin-autorouter
|
||||||
|
|
||||||
|
借鉴 [Nuxt.js](https://zh.nuxtjs.org/) 的路由源码实现。可以根据存放Vue-Router页面的文件夹结构自动生成Vue-Router配置文件。
|
||||||
|
|
||||||
|
**相信我,你会中毒的,妈妈再也不用担心我手动低效的去`Ctrl + C`,`Ctrl + V`了,一切交给插件自动生成路由配置文件,我们要做的就是按照规则维护好文件夹结构,世界突然美妙了。**
|
||||||
|
|
||||||
|
> 注意:这个插件目前为止还没有改成通用的插件包,有这个考虑。不过现阶段主要用于 [Vue3template](https://github.com/helpcode/Vue3template) 这个脚手架项目。后面还会考虑再开发一个脚手架项目的`cli`命令行工具,实现类似`Vue-cli`通过命令进行项目的初始化等功能。
|
||||||
|
|
||||||
|
## 1:安装(Vue3template默认已安装配置好,可直接使用)
|
||||||
|
|
||||||
|
注意这是一个基于[Vue-cli 3.0](https://cli.vuejs.org/zh/)也就是 vue-cli-service 开发的插件,不支持老版本Vue 2.0的脚手架哦,请注意了!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vue add vue-cli-plugin-autorouter
|
||||||
|
```
|
||||||
|
|
||||||
|
`add`安装的时候会自动向你项目的`package.json`的`devDependencies`注入下面依赖:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
"glob": "^7.1.3",
|
||||||
|
"pify": "^4.0.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
这是 `vue-cli-service`插件开发`Generator`自动注入的,也是本插件需要使用到的依赖。请勿随意删除。
|
||||||
|
|
||||||
|
## 2:配置
|
||||||
|
|
||||||
|
在`vue.config.js`中你可以增加`pluginOptions`配置节点,实现对插件的自定义化需求定制:
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
// ...
|
||||||
|
pluginOptions: {
|
||||||
|
route: {
|
||||||
|
// 默认:page。存放Vue路由页面的文件夹名称
|
||||||
|
TemplateFolderName: 'page',
|
||||||
|
// 默认:./src/application。从src/开始到TemplateFolderName文件夹父一级文件夹相对路径
|
||||||
|
RootFolderName: './src/application',
|
||||||
|
// 默认 src/core/config/route.config.ts。生成的配置文件保存路径,相对插件的位置来。
|
||||||
|
SaveConfigPath: '../../../src/core/config/route.config.ts'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**然后你就可以很爽的直接使用命令,注意这个命令是用来自动生成配置文件的:**
|
||||||
|
```bash
|
||||||
|
vue-cli-service route
|
||||||
|
```
|
||||||
|
|
||||||
|
> 注意:每次项目新增页面后,请重新执行此命令用以生成新的路由配置文件!!
|
||||||
|
|
||||||
|
不过,推荐在项目的`package.json`中做如下配置:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
"scripts": {
|
||||||
|
"serve": "npm run route && vue-cli-service serve",
|
||||||
|
"route": "vue-cli-service route",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:一定要在 `vue-cli-service serve`命令运行前,先跑`vue-cli-service route`来扫描`src/application/page`的文件结构进而自动生成`Vue-Router`的配置文件。默认配置文件保存在:`src/core/config/route.config.ts`中。
|
||||||
|
|
||||||
|
## 3:卸载
|
||||||
|
|
||||||
|
东西再好,总有些开发者拒绝学习,或者拒绝尝试新的东西,喜欢固守自己已熟知的技术栈,那么下面提供卸载`Vue3template`自带的` vue-cli-plugin-autorouter`教程。
|
||||||
|
|
||||||
|
### 3.1: 删除依赖(两种方式)
|
||||||
|
|
||||||
|
- 1: 使用npm命令卸载依赖:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm uninstall --save glob pify vue-cli-plugin-autorouter
|
||||||
|
```
|
||||||
|
|
||||||
|
- 2: 从`package.json`中手动删除下面依赖信息
|
||||||
|
|
||||||
|
```text
|
||||||
|
"glob": "^7.1.3",
|
||||||
|
"pify": "^4.0.1",
|
||||||
|
"vue-cli-plugin-autorouter": "^1.1.8",
|
||||||
|
```
|
||||||
|
|
||||||
|
然后删除项目`node_modules`,在重新`npm i`。
|
||||||
|
|
||||||
|
### 3.2: vue.config.js
|
||||||
|
|
||||||
|
从`vue.config.js`中你删除`pluginOptions`配置节点。
|
||||||
|
|
||||||
|
|
||||||
|
### 3.3: 修改源码
|
||||||
|
|
||||||
|
1: 从`src/core/config`中删除文件`route.config.ts`。
|
||||||
|
|
||||||
|
2:然后修改:`index.config.ts`,去除:`import { AutoRoutesConfig } from './route.config';`
|
||||||
|
|
||||||
|
3:之后修改:`RouterConfigUrl`中的`routes`对象,`routes`对象的内容需要你自己手动
|
||||||
|
|
||||||
|
> 注意:`RouterConfigUrl` 中的 `routes` 需要你自己手动配置了,这里提供一份配置参考:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public static RouterConfigUrl: RouterOptions = {
|
||||||
|
mode: 'hash',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
path: "/user",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user-one",
|
||||||
|
path: "/user/one",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/one.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "index",
|
||||||
|
path: "/",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 【新增功能】4:路由meta配置
|
||||||
|
|
||||||
|
在`page/`文件夹的组件中使用可以直接使用自定义标签`<route-meta></route-meta>`来实现对路由`meta`的直接配置,插件会提取`<route-meta></route-meta>`中的代码直接注入到生成的路由配置文件中。下面请看使用案例:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<route-meta>
|
||||||
|
{
|
||||||
|
"isLogin": false,
|
||||||
|
"title": "首页"
|
||||||
|
}
|
||||||
|
</route-meta>
|
||||||
|
<template lang="pug">
|
||||||
|
.home
|
||||||
|
h2 测试标题
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意这里`route-meta`标签中填的必须是一个`JSON`对象,注意书写格式,不能有误!!**
|
||||||
|
|
||||||
|
那么自动生成的路由配置如下:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
name: "index",
|
||||||
|
path: "/",
|
||||||
|
component: () => import(/* webpackChunkName: 'index' */ '@/page/index.vue'),
|
||||||
|
meta: {
|
||||||
|
isLogin: false,
|
||||||
|
title: "首页"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5:使用
|
||||||
|
|
||||||
|
这里使用请注意文件夹结构,多看几次下面的例子加强理解,以便能够更好的组织自己的路由结构!!
|
||||||
|
|
||||||
|
|
||||||
|
### 5.1: 基础路由
|
||||||
|
|
||||||
|
基础路由很简单,直接在`page/`文件下新建`vue`组件即可,插件会根据文件结构自动生成路由配置文件!!
|
||||||
|
|
||||||
|
假设 page 的目录结构如下:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
pages/
|
||||||
|
--| user/
|
||||||
|
-----| index.vue
|
||||||
|
-----| one.vue
|
||||||
|
--| index.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
那么自动生成的路由配置如下:
|
||||||
|
|
||||||
|
```js
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
path: "/user",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user-one",
|
||||||
|
path: "/user/one",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/one.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "index",
|
||||||
|
path: "/",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2: 动态路由(带参数)
|
||||||
|
|
||||||
|
如果路由需要参数,那么可以按照命名的规则:`_参数名.vue`,在`user/`文件夹创建`Vue`组件。例如这里的:`_id.vue`,其实这里的 `_id.vue`就相当于我们平时开发时用的`user_info.vue`组件。
|
||||||
|
|
||||||
|
假设 page 的目录结构如下:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
page/
|
||||||
|
--| user/
|
||||||
|
-----| _id.vue
|
||||||
|
--| index.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
那么自动生成的路由配置如下:
|
||||||
|
|
||||||
|
```js
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "user-id",
|
||||||
|
path: "/user/:id?",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/_id.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "index",
|
||||||
|
path: "/",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
这里我们有了`user-id`组件(相当于 `user_info.vue`),那么`user`首页组件如何添加?其实很简单!
|
||||||
|
|
||||||
|
基于上面的文件结构在`user/`里面在创建一个`index.vue`组件即可,默认文件夹下面的`index.vue`作为路由的首页
|
||||||
|
|
||||||
|
改变后的文件结构如下:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
page/
|
||||||
|
--| user/
|
||||||
|
-----| _id.vue # 这个相当于平时开发的 user_info.vue,个人中心的详情页面
|
||||||
|
-----| index.vue # user首页,类似个人中心
|
||||||
|
--| index.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
那么自动生成的路由配置如下:
|
||||||
|
|
||||||
|
```js
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
path: "/user",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user-id",
|
||||||
|
path: "/user/:id",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/_id.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "index",
|
||||||
|
path: "/",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
````
|
||||||
|
|
||||||
|
### 5.3: 嵌套路由
|
||||||
|
|
||||||
|
创建内嵌子路由,上面我们已经有了`user/`文件夹,那么我们可以在`user/`文件夹同级目录创建一个名字一样的`Vue`组件,这里添加:`user.vue`!
|
||||||
|
|
||||||
|
假设 page 的目录结构如下:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
page/
|
||||||
|
--| user/
|
||||||
|
-----| _id.vue
|
||||||
|
-----| index.vue
|
||||||
|
--| user.vue
|
||||||
|
--| index.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
那么自动生成的路由配置如下:
|
||||||
|
|
||||||
|
```js
|
||||||
|
[
|
||||||
|
{
|
||||||
|
path: "/user",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user.vue'),
|
||||||
|
meta: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
path: "",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user-id",
|
||||||
|
path: ":id",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/user/_id.vue'),
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "index",
|
||||||
|
path: "/",
|
||||||
|
component: () => import(/* webpackChunkName: '[request]' */ '@/page/index.vue'),
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
> 记住:这是嵌套路由所以别忘记在`user.vue`组件中添加:`router-view` 来展示子路由的页面。
|
||||||
1
generator/.pydio
Normal file
1
generator/.pydio
Normal file
@@ -0,0 +1 @@
|
|||||||
|
7d22662f-47a9-47f7-9945-1c842bb893aa
|
||||||
11
generator/index.js
Normal file
11
generator/index.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = (api, options, rootOptions) => {
|
||||||
|
api.extendPackage({
|
||||||
|
devDependencies: {
|
||||||
|
"@babel/generator": "^7.11.4",
|
||||||
|
"@babel/types": "^7.11.0",
|
||||||
|
"@babel/parser": "^7.11.4",
|
||||||
|
"glob": "^7.1.3",
|
||||||
|
"pify": "^4.0.1"
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
17
index.js
Normal file
17
index.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const creatRouter = require('./service/regist-route')
|
||||||
|
require('./utils/welcome');
|
||||||
|
|
||||||
|
module.exports = (api, projectOptions) => {
|
||||||
|
api.registerCommand('route', {
|
||||||
|
description: '根据page文件结构自动生成路由配置文件',
|
||||||
|
usage: 'vue-cli-service route',
|
||||||
|
options: {}
|
||||||
|
}, (args) => {
|
||||||
|
let routeParams = projectOptions.pluginOptions.route;
|
||||||
|
creatRouter.creatRouter(false, routeParams);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.defaultModes = {
|
||||||
|
build: 'development'
|
||||||
|
};
|
||||||
159
package-lock.json
generated
Normal file
159
package-lock.json
generated
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
{
|
||||||
|
"name": "vue-cli-plugin-autorouter",
|
||||||
|
"version": "1.3.3",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/generator": {
|
||||||
|
"version": "7.11.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz",
|
||||||
|
"integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/types": "^7.11.0",
|
||||||
|
"jsesc": "^2.5.1",
|
||||||
|
"source-map": "^0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@babel/helper-validator-identifier": {
|
||||||
|
"version": "7.10.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
|
||||||
|
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
|
||||||
|
},
|
||||||
|
"@babel/parser": {
|
||||||
|
"version": "7.11.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz",
|
||||||
|
"integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA=="
|
||||||
|
},
|
||||||
|
"@babel/types": {
|
||||||
|
"version": "7.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
|
||||||
|
"integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/helper-validator-identifier": "^7.10.4",
|
||||||
|
"lodash": "^4.17.19",
|
||||||
|
"to-fast-properties": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"balanced-match": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
|
},
|
||||||
|
"brace-expansion": {
|
||||||
|
"version": "1.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
|
"requires": {
|
||||||
|
"balanced-match": "^1.0.0",
|
||||||
|
"concat-map": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"concat-map": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
|
},
|
||||||
|
"de-indent": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0="
|
||||||
|
},
|
||||||
|
"fs.realpath": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||||
|
},
|
||||||
|
"glob": {
|
||||||
|
"version": "7.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||||
|
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||||
|
"requires": {
|
||||||
|
"fs.realpath": "^1.0.0",
|
||||||
|
"inflight": "^1.0.4",
|
||||||
|
"inherits": "2",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"path-is-absolute": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"he": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||||
|
},
|
||||||
|
"inflight": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
|
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||||
|
"requires": {
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
|
},
|
||||||
|
"jsesc": {
|
||||||
|
"version": "2.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||||
|
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
|
||||||
|
},
|
||||||
|
"lodash": {
|
||||||
|
"version": "4.17.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||||
|
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||||
|
},
|
||||||
|
"minimatch": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
|
"requires": {
|
||||||
|
"brace-expansion": "^1.1.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
|
"requires": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"path-is-absolute": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||||
|
},
|
||||||
|
"pify": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
|
||||||
|
},
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.5.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||||
|
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||||
|
},
|
||||||
|
"to-fast-properties": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
|
||||||
|
},
|
||||||
|
"vue-template-compiler": {
|
||||||
|
"version": "2.6.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz",
|
||||||
|
"integrity": "sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==",
|
||||||
|
"requires": {
|
||||||
|
"de-indent": "^1.0.2",
|
||||||
|
"he": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
package.json
Normal file
25
package.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "vue-cli-plugin-tsx-autorouter",
|
||||||
|
"version": "1.3.8",
|
||||||
|
"description": "vue cli plugin to auto add router tsx",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "bmy",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/generator": "^7.11.4",
|
||||||
|
"@babel/types": "^7.11.0",
|
||||||
|
"@babel/parser": "^7.11.4",
|
||||||
|
"glob": "^7.1.3",
|
||||||
|
"pify": "^4.0.1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"vue",
|
||||||
|
"vue-cli",
|
||||||
|
"vue-router",
|
||||||
|
"autorouter"
|
||||||
|
],
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
||||||
1
service/.pydio
Normal file
1
service/.pydio
Normal file
@@ -0,0 +1 @@
|
|||||||
|
876a8496-8207-43a5-ab7b-f46a75d7118a
|
||||||
309
service/regist-route.js
Normal file
309
service/regist-route.js
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
const Glob = require('glob');
|
||||||
|
const pify = require('pify');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const { parse } = require('@babel/parser');
|
||||||
|
const t = require('@babel/types');
|
||||||
|
const generate = require('@babel/generator');
|
||||||
|
|
||||||
|
const glob = pify(Glob);
|
||||||
|
let globPath = "";
|
||||||
|
let OptionSetting = {};
|
||||||
|
|
||||||
|
// 获取文件路径,构造路由参数数组
|
||||||
|
generateRoutesAndFiles = async (PagePath) => {
|
||||||
|
const files = {};
|
||||||
|
|
||||||
|
(await glob(`${PagePath}/**/*.{vue,js,tsx,jsx}`, {
|
||||||
|
cwd: path.resolve(process.cwd(), OptionSetting.RootFolderName),
|
||||||
|
ignore: ['**/*.test.*', '**/*.spec.*', '**/-*.*']
|
||||||
|
})).forEach((f) => {
|
||||||
|
const key = f.replace(/\.(js|vue)$/, '')
|
||||||
|
if (/\.vue$/.test(f) || !files[key]) {
|
||||||
|
files[key] = f.replace(/('|")/g, '\\$1')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return createRoutes(
|
||||||
|
Object.values(files),
|
||||||
|
path.resolve(process.cwd(), OptionSetting.RootFolderName),
|
||||||
|
PagePath
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 填充路由配置
|
||||||
|
// `Utils.AsyncComponentHook('${camelCase(keys.join('-').replace('_', ''))}')`
|
||||||
|
const createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
||||||
|
const routes = [];
|
||||||
|
files.forEach((file) => {
|
||||||
|
const keys = file
|
||||||
|
.replace(RegExp(`^${pagesDir}`), '')
|
||||||
|
.replace(/\.(vue|js|tsx)$/, '')
|
||||||
|
.replace(/\/{2,}/g, '/')
|
||||||
|
.split('/')
|
||||||
|
.slice(1);
|
||||||
|
const route = {
|
||||||
|
name: '',
|
||||||
|
path: '',
|
||||||
|
component: `_() => import(/* webpackChunkName: '${keys.toString().replace(/,/g, "")}' */ '@${pagesDir}/${keys.join('/')}')`,
|
||||||
|
meta: routeMeta(file)
|
||||||
|
};
|
||||||
|
let parent = routes;
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
const sanitizedKey = key.startsWith('_') ? key.substr(1) : key;
|
||||||
|
|
||||||
|
route.name = route.name
|
||||||
|
? route.name + '-' + sanitizedKey
|
||||||
|
: sanitizedKey;
|
||||||
|
|
||||||
|
route.name += key === '_' ? 'all' : '';
|
||||||
|
const child = parent.find(parentRoute => parentRoute.name === route.name);
|
||||||
|
|
||||||
|
if (child) {
|
||||||
|
child.children = child.children || [];
|
||||||
|
parent = child.children;
|
||||||
|
route.path = '';
|
||||||
|
} else if (key === 'index' && i + 1 === keys.length) {
|
||||||
|
route.path += i > 0 ? '' : '/';
|
||||||
|
} else {
|
||||||
|
route.path += '/' + getRoutePathExtension(key);
|
||||||
|
|
||||||
|
if (key.startsWith('_') && key.length > 1) {
|
||||||
|
route.path += '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
parent.push(route);
|
||||||
|
});
|
||||||
|
|
||||||
|
sortRoutes(routes);
|
||||||
|
return cleanChildrenRoutes(routes)
|
||||||
|
};
|
||||||
|
|
||||||
|
const startsWithAlias = aliasArray => str => aliasArray.some(c => str.startsWith(c));
|
||||||
|
const reqSep = /\//g;
|
||||||
|
const sysSep = escapeRegExp(path.sep);
|
||||||
|
const normalize = string => string.replace(reqSep, sysSep);
|
||||||
|
const startsWithSrcAlias = startsWithAlias(['@', '~']);
|
||||||
|
|
||||||
|
function routeMeta(f) {
|
||||||
|
let meta = {};
|
||||||
|
const VuePath = path.join(__dirname,`../../.${OptionSetting.RootFolderName}/${f}`);
|
||||||
|
let VueSource = fs.readFileSync(VuePath).toString();
|
||||||
|
// 将tsx字符串代码转换成ast语法树
|
||||||
|
const ast = parse(VueSource, {
|
||||||
|
sourceType: 'module',
|
||||||
|
plugins: ['typescript', 'jsx', 'classProperties',
|
||||||
|
['decorators', { decoratorsBeforeExport: true }]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
// 从语法树中找到类私有属性 private RouterMeta
|
||||||
|
output = ""
|
||||||
|
ast.program.body.forEach((v, i) => {
|
||||||
|
if (t.isExportDefaultDeclaration(v)) {
|
||||||
|
v.declaration.body.body.forEach((b)=>{
|
||||||
|
if (t.isClassProperty(b)) {
|
||||||
|
if (t.isIdentifier(b.key) && b.key.name == 'RouterMeta') {
|
||||||
|
// 将 私有属性 RouterMeta 的值从语法树转换为js代码
|
||||||
|
output = generate.default(b.value, {
|
||||||
|
compact: true,
|
||||||
|
}).code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if(output.length != 0) {
|
||||||
|
return eval(JSON.stringify(output));
|
||||||
|
} else {
|
||||||
|
return JSON.stringify({
|
||||||
|
test: `请在组件配置:route-meta 标签,参考文档:https://www.npmjs.com/package/vue-cli-plugin-autorouter`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const r = function r(...args) {
|
||||||
|
const lastArg = args[args.length - 1];
|
||||||
|
if (startsWithSrcAlias(lastArg)) {
|
||||||
|
return wp(lastArg)
|
||||||
|
}
|
||||||
|
return wp(path.resolve(...args.map(normalize)))
|
||||||
|
};
|
||||||
|
|
||||||
|
function baseToString(value) {
|
||||||
|
if (typeof value == 'string') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (isArray_1(value)) {
|
||||||
|
return _arrayMap(value, baseToString) + '';
|
||||||
|
}
|
||||||
|
if (isSymbol_1(value)) {
|
||||||
|
return symbolToString ? symbolToString.call(value) : '';
|
||||||
|
}
|
||||||
|
var result = (value + '');
|
||||||
|
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toString(value) {
|
||||||
|
return value == null ? '' : baseToString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeRegExp(string) {
|
||||||
|
const reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
|
||||||
|
reHasRegExpChar = RegExp(reRegExpChar.source);
|
||||||
|
string = toString(string);
|
||||||
|
return (string && reHasRegExpChar.test(string)) ?
|
||||||
|
string.replace(reRegExpChar, '\\$&') :
|
||||||
|
string;
|
||||||
|
}
|
||||||
|
const isWindows = /^win/.test(process.platform);
|
||||||
|
|
||||||
|
const wp = function wp(p = '') {
|
||||||
|
if (isWindows) {
|
||||||
|
return p.replace(/\\/g, '\\\\')
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRoutePathExtension = (key) => {
|
||||||
|
if (key === '_') {
|
||||||
|
return '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.startsWith('_')) {
|
||||||
|
return `:${key.substr(1)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return key
|
||||||
|
};
|
||||||
|
|
||||||
|
const DYNAMIC_ROUTE_REGEX = /^\/(:|\*)/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序路由
|
||||||
|
* @param {*} routes
|
||||||
|
*/
|
||||||
|
function sortRoutes(routes) {
|
||||||
|
routes.sort((a, b) => {
|
||||||
|
if (!a.path.length) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if (!b.path.length) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if (a.path === '/') {
|
||||||
|
return DYNAMIC_ROUTE_REGEX.test(b.path) ? -1 : 1
|
||||||
|
}
|
||||||
|
if (b.path === '/') {
|
||||||
|
return DYNAMIC_ROUTE_REGEX.test(a.path) ? 1 : -1
|
||||||
|
}
|
||||||
|
|
||||||
|
let i
|
||||||
|
let res = 0
|
||||||
|
let y = 0
|
||||||
|
let z = 0
|
||||||
|
const _a = a.path.split('/')
|
||||||
|
const _b = b.path.split('/')
|
||||||
|
for (i = 0; i < _a.length; i++) {
|
||||||
|
if (res !== 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
y = _a[i] === '*' ? 2 : _a[i].includes(':') ? 1 : 0
|
||||||
|
z = _b[i] === '*' ? 2 : _b[i].includes(':') ? 1 : 0
|
||||||
|
res = y - z
|
||||||
|
// If a.length >= b.length
|
||||||
|
if (i === _b.length - 1 && res === 0) {
|
||||||
|
// unless * found sort by level, then alphabetically
|
||||||
|
res = _a[i] === '*' ? -1 : (
|
||||||
|
_a.length === _b.length ? a.path.localeCompare(b.path) : (_a.length - _b.length)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res === 0) {
|
||||||
|
res = _a[i - 1] === '*' && _b[i] ? 1 : (
|
||||||
|
_a.length === _b.length ? a.path.localeCompare(b.path) : (_a.length - _b.length)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
|
||||||
|
routes.forEach((route) => {
|
||||||
|
if (route.children) {
|
||||||
|
sortRoutes(route.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanChildrenRoutes(routes, isChild = false) {
|
||||||
|
let start = -1
|
||||||
|
const routesIndex = []
|
||||||
|
routes.forEach((route) => {
|
||||||
|
if (/-index$/.test(route.name) || route.name === 'index') {
|
||||||
|
const res = route.name.split('-')
|
||||||
|
const s = res.indexOf('index')
|
||||||
|
start = start === -1 || s < start ? s : start
|
||||||
|
routesIndex.push(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
routes.forEach((route) => {
|
||||||
|
route.path = isChild ? route.path.replace('/', '') : route.path
|
||||||
|
if (route.path.includes('?')) {
|
||||||
|
const names = route.name.split('-')
|
||||||
|
const paths = route.path.split('/')
|
||||||
|
if (!isChild) {
|
||||||
|
paths.shift()
|
||||||
|
}
|
||||||
|
routesIndex.forEach((r) => {
|
||||||
|
const i = r.indexOf('index') - start
|
||||||
|
if (i < paths.length) {
|
||||||
|
for (let a = 0; a <= i; a++) {
|
||||||
|
if (a === i) {
|
||||||
|
paths[a] = paths[a].replace('?', '')
|
||||||
|
}
|
||||||
|
if (a < i && names[a] !== r[a]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
route.path = (isChild ? '' : '/') + paths.join('/')
|
||||||
|
}
|
||||||
|
route.name = route.name.replace(/-index$/, '')
|
||||||
|
if (route.children) {
|
||||||
|
if (route.children.find(child => child.path === '')) {
|
||||||
|
delete route.name
|
||||||
|
}
|
||||||
|
route.children = cleanChildrenRoutes(route.children, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
|
function camelCase(string) {
|
||||||
|
return string.replace(/-([a-z])/g, function (all, letter) {
|
||||||
|
return letter.toUpperCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.creatRouter = (flag = false, root) => {
|
||||||
|
if (flag) return;
|
||||||
|
OptionSetting = root;
|
||||||
|
generateRoutesAndFiles(OptionSetting.TemplateFolderName).then(res => {
|
||||||
|
let string = `// 根据page目录结构,自动生成的路由配置文件\n// 参考Nuxt.js:https://zh.nuxtjs.org/guide/routing\n// @ts-ignore\n\n`;
|
||||||
|
|
||||||
|
string += `export const AutoRoutesConfig = ${JSON.stringify(res, null, 2)};`
|
||||||
|
.replace(/"component": "(\w+?)"/g, `"component": $1`)
|
||||||
|
.replace(/"(\w+?)":/g, '$1:')
|
||||||
|
.replace(/"_()/g, "")
|
||||||
|
.replace(/"{/g, "{")
|
||||||
|
.replace(/}"/g, "}")
|
||||||
|
.replace(/\'\)\"/g, "')")
|
||||||
|
|
||||||
|
let buildPath = path.resolve(process.cwd(), path.join(__dirname, OptionSetting.SaveConfigPath));
|
||||||
|
fs.writeFileSync(buildPath, string);
|
||||||
|
})
|
||||||
|
};
|
||||||
1
utils/.pydio
Normal file
1
utils/.pydio
Normal file
@@ -0,0 +1 @@
|
|||||||
|
57690bf2-4361-4277-ae8c-5aab54aeb228
|
||||||
12
utils/welcome.js
Normal file
12
utils/welcome.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
const { readFileSync, writeFileSync } = require("fs");
|
||||||
|
const { join } = require("path");
|
||||||
|
const package = require("../package.json");
|
||||||
|
const Path = '../../@vue/cli-service/lib/commands/serve.js';
|
||||||
|
let serve = (readFileSync(join(__dirname, Path))).toString();
|
||||||
|
serve = serve.replace('Starting development server...',"正在启动开发服务器...");
|
||||||
|
serve = serve.replace('App running at:',`🎉 欢迎使用 ${package.name}\n 🎉 该插件基于本人另一个项目[vue-cli-plugin-autorouter]适配自己的VueClassApi + Tsx 的脚手架而来 \n\n 📦 项目地址:https://www.npmjs.com/package/vue-cli-plugin-autorouter\n 👨💻 作者:bmy\n 📞 Github:https://github.com/helpcode\n 应用运行在:`);
|
||||||
|
serve = serve.replace('- Local:'," - 本地:");
|
||||||
|
serve = serve.replace('- Network:'," - 网络:");
|
||||||
|
serve = serve.replace('Note that the development build is not optimized.',"注意开发阶段项目没有做优化。");
|
||||||
|
serve = serve.replace('To create a production build, run',"如果要创建生产代码,请运行命令: ");
|
||||||
|
writeFileSync(join(__dirname, Path),serve);
|
||||||
Reference in New Issue
Block a user