Skip to content

Commit 246ae67

Browse files
pksunkarahaoqunjiang
authored andcommitted
feat!: make router a separate plugin (#4196)
* refactor: move router to its own plugin * refactor: rename routerHistoryMode option to historyMode * test: add @vue/cli-plugin-router tests * feat: change src/router.js for most common use cases * fix: fix cli-ui tests * docs: Remove router root option from docs * fix: add support for legacy router option
1 parent 9eadfe1 commit 246ae67

File tree

33 files changed

+305
-187
lines changed

33 files changed

+305
-187
lines changed

docs/dev-guide/ui-api.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1274,15 +1274,15 @@ const ROUTER = 'vue-router-add'
12741274

12751275
api.onViewOpen(({ view }) => {
12761276
if (view.id === 'vue-project-plugins') {
1277-
if (!api.hasPlugin('vue-router')) {
1277+
if (!api.hasPlugin('router')) {
12781278
api.addSuggestion({
12791279
id: ROUTER,
12801280
type: 'action',
12811281
label: 'org.vue.cli-service.suggestions.vue-router-add.label',
12821282
message: 'org.vue.cli-service.suggestions.vue-router-add.message',
12831283
link: 'https://router.vuejs.org/',
12841284
async handler () {
1285-
await install(api, 'vue-router')
1285+
await install(api, 'router')
12861286
}
12871287
})
12881288
}

docs/guide/plugins-and-presets.md

+2-9
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ You can pass generator options to the installed plugin (this will skip the promp
5252
vue add @vue/eslint --config airbnb --lintOn save
5353
```
5454

55-
`vue-router` and `vuex` are special cases - they do not have their own plugins, but you can add them nonetheless:
56-
57-
``` bash
58-
vue add router
59-
vue add vuex
60-
```
61-
6255
If a plugin is already installed, you can skip the installation and only invoke its generator with the `vue invoke` command. The command takes the same arguments as `vue add`.
6356

6457
::: tip
@@ -112,15 +105,15 @@ Here's an example preset:
112105
``` json
113106
{
114107
"useConfigFiles": true,
115-
"router": true,
116108
"vuex": true,
117109
"cssPreprocessor": "sass",
118110
"plugins": {
119111
"@vue/cli-plugin-babel": {},
120112
"@vue/cli-plugin-eslint": {
121113
"config": "airbnb",
122114
"lintOn": ["save", "commit"]
123-
}
115+
},
116+
"@vue/cli-plugin-router": {}
124117
}
125118
}
126119
```

docs/ru/dev-guide/ui-api.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1274,15 +1274,15 @@ const ROUTER = 'vue-router-add'
12741274

12751275
api.onViewOpen(({ view }) => {
12761276
if (view.id === 'vue-project-plugins') {
1277-
if (!api.hasPlugin('vue-router')) {
1277+
if (!api.hasPlugin('router')) {
12781278
api.addSuggestion({
12791279
id: ROUTER,
12801280
type: 'action',
12811281
label: 'org.vue.cli-service.suggestions.vue-router-add.label',
12821282
message: 'org.vue.cli-service.suggestions.vue-router-add.message',
12831283
link: 'https://router.vuejs.org/',
12841284
async handler () {
1285-
await install(api, 'vue-router')
1285+
await install(api, 'router')
12861286
}
12871287
})
12881288
}

docs/ru/guide/plugins-and-presets.md

+2-9
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ vue add @foo/bar
5252
vue add @vue/eslint --config airbnb --lintOn save
5353
```
5454

55-
Добавление `vue-router` и `vuex` — особый случай, у них нет собственных плагинов, но вы тем не менее можете их добавить:
56-
57-
``` bash
58-
vue add router
59-
vue add vuex
60-
```
61-
6255
Если плагин уже установлен, вы можете пропустить установку и только вызвать его генератор с помощью команды `vue invoke`. Команда принимает такие же аргументы, как и `vue add`.
6356

6457
::: tip Совет
@@ -112,15 +105,15 @@ vue add vuex
112105
``` json
113106
{
114107
"useConfigFiles": true,
115-
"router": true,
116108
"vuex": true,
117109
"cssPreprocessor": "sass",
118110
"plugins": {
119111
"@vue/cli-plugin-babel": {},
120112
"@vue/cli-plugin-eslint": {
121113
"config": "airbnb",
122114
"lintOn": ["save", "commit"]
123-
}
115+
},
116+
"@vue/cli-plugin-router": {}
124117
}
125118
}
126119
```

docs/zh/guide/plugins-and-presets.md

+2-9
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ vue add @foo/bar
5252
vue add @vue/eslint --config airbnb --lintOn save
5353
```
5454

55-
`vue-router``vuex` 的情况比较特殊——它们并没有自己的插件,但是你仍然可以这样添加它们:
56-
57-
``` bash
58-
vue add router
59-
vue add vuex
60-
```
61-
6255
如果一个插件已经被安装,你可以使用 `vue invoke` 命令跳过安装过程,只调用它的生成器。这个命令会接受和 `vue add` 相同的参数。
6356

6457
::: tip 提示
@@ -112,15 +105,15 @@ vue add vuex
112105
``` json
113106
{
114107
"useConfigFiles": true,
115-
"router": true,
116108
"vuex": true,
117109
"cssPreprocessor": "sass",
118110
"plugins": {
119111
"@vue/cli-plugin-babel": {},
120112
"@vue/cli-plugin-eslint": {
121113
"config": "airbnb",
122114
"lintOn": ["save", "commit"]
123-
}
115+
},
116+
"@vue/cli-plugin-router": {}
124117
}
125118
}
126119
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__tests__
2+
__mocks__
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# @vue/cli-plugin-router
2+
3+
> router plugin for vue-cli
4+
5+
## Installing in an Already Created Project
6+
7+
``` sh
8+
vue add @vue/router
9+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
const generateWithPlugin = require('@vue/cli-test-utils/generateWithPlugin')
2+
3+
test('base', async () => {
4+
const { files, pkg } = await generateWithPlugin({
5+
id: 'router',
6+
apply: require('../generator'),
7+
options: {}
8+
})
9+
10+
expect(files['src/router/index.js']).toBeTruthy()
11+
expect(files['src/router/index.js']).not.toMatch('history')
12+
expect(files['src/views/About.vue']).toBeTruthy()
13+
expect(files['src/views/Home.vue']).toBeTruthy()
14+
expect(files['src/App.vue']).toMatch('<router-link to="/">Home</router-link>')
15+
expect(files['src/App.vue']).not.toMatch('<script>')
16+
expect(files['src/App.vue']).toMatch('#nav a.router-link-exact-active')
17+
18+
expect(pkg.dependencies).toHaveProperty('vue-router')
19+
})
20+
21+
test('history mode', async () => {
22+
const { files, pkg } = await generateWithPlugin({
23+
id: 'router',
24+
apply: require('../generator'),
25+
options: {
26+
historyMode: true
27+
}
28+
})
29+
30+
expect(files['src/router/index.js']).toBeTruthy()
31+
expect(files['src/router/index.js']).toMatch('history')
32+
expect(files['src/views/About.vue']).toBeTruthy()
33+
expect(files['src/views/Home.vue']).toBeTruthy()
34+
expect(files['src/App.vue']).toMatch('<router-link to="/">Home</router-link>')
35+
expect(files['src/App.vue']).not.toMatch('<script>')
36+
expect(files['src/App.vue']).toMatch('#nav a.router-link-exact-active')
37+
38+
expect(pkg.dependencies).toHaveProperty('vue-router')
39+
})
40+
41+
test('use with Babel', async () => {
42+
const { pkg, files } = await generateWithPlugin([
43+
{
44+
id: 'babel',
45+
apply: require('@vue/cli-plugin-babel/generator'),
46+
options: {}
47+
},
48+
{
49+
id: 'router',
50+
apply: require('../generator'),
51+
options: {}
52+
}
53+
])
54+
55+
expect(files['src/router/index.js']).toBeTruthy()
56+
expect(files['src/router/index.js']).toMatch('component: () => import')
57+
expect(files['src/views/About.vue']).toBeTruthy()
58+
expect(files['src/views/Home.vue']).toBeTruthy()
59+
expect(files['src/App.vue']).toMatch('<router-link to="/">Home</router-link>')
60+
expect(files['src/App.vue']).not.toMatch('<script>')
61+
expect(files['src/App.vue']).toMatch('#nav a.router-link-exact-active')
62+
63+
expect(pkg.dependencies).toHaveProperty('vue-router')
64+
})

packages/@vue/cli-service/generator/router/index.js renamed to packages/@vue/cli-plugin-router/generator/index.js

+6-18
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,22 @@
11
module.exports = (api, options = {}) => {
2+
api.assertCliVersion('^4.0.0-alpha.3')
3+
api.assertCliServiceVersion('^4.0.0-alpha.3')
4+
25
api.injectImports(api.entryFile, `import router from './router'`)
36
api.injectRootOptions(api.entryFile, `router`)
7+
48
api.extendPackage({
59
dependencies: {
610
'vue-router': '^3.0.6'
711
}
812
})
13+
914
api.render('./template', {
10-
historyMode: options.routerHistoryMode,
15+
historyMode: options.historyMode,
1116
doesCompile: api.hasPlugin('babel') || api.hasPlugin('typescript')
1217
})
1318

1419
if (api.invoking) {
15-
api.postProcessFiles(files => {
16-
const appFile = files[`src/App.vue`]
17-
if (appFile) {
18-
files[`src/App.vue`] = appFile.replace(/^<template>[^]+<\/script>/, `
19-
<template>
20-
<div id="app">
21-
<div id="nav">
22-
<router-link to="/">Home</router-link> |
23-
<router-link to="/about">About</router-link>
24-
</div>
25-
<router-view/>
26-
</div>
27-
</template>
28-
`.trim())
29-
}
30-
})
31-
3220
if (api.hasPlugin('typescript')) {
3321
/* eslint-disable-next-line node/no-extraneous-require */
3422
const convertFiles = require('@vue/cli-plugin-typescript/generator/convert')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
extend: '@vue/cli-service/generator/template/src/App.vue'
3+
replace:
4+
- !!js/regexp /<template>[^]*?<\/template>/
5+
- !!js/regexp /\n<script>[^]*?<\/script>\n/
6+
- !!js/regexp / margin-top[^]*?<\/style>/
7+
---
8+
9+
<%# REPLACE %>
10+
<template>
11+
<div id="app">
12+
<div id="nav">
13+
<router-link to="/">Home</router-link> |
14+
<router-link to="/about">About</router-link>
15+
</div>
16+
<router-view/>
17+
</div>
18+
</template>
19+
<%# END_REPLACE %>
20+
21+
<%# REPLACE %>
22+
<%# END_REPLACE %>
23+
24+
<%# REPLACE %>
25+
}
26+
27+
<%_ if (rootOptions.cssPreprocessor !== 'stylus') { _%>
28+
<%_ if (!rootOptions.cssPreprocessor) { _%>
29+
#nav {
30+
padding: 30px;
31+
}
32+
33+
#nav a {
34+
font-weight: bold;
35+
color: #2c3e50;
36+
}
37+
38+
#nav a.router-link-exact-active {
39+
color: #42b983;
40+
}
41+
<%_ } else { _%>
42+
#nav {
43+
padding: 30px;
44+
45+
a {
46+
font-weight: bold;
47+
color: #2c3e50;
48+
49+
&.router-link-exact-active {
50+
color: #42b983;
51+
}
52+
}
53+
}
54+
<%_ } _%>
55+
<%_ } else { _%>
56+
#nav
57+
padding 30px
58+
a
59+
font-weight bold
60+
color #2c3e50
61+
&.router-link-exact-active
62+
color #42b983
63+
<%_ } _%>
64+
</style>
65+
<%# END_REPLACE %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Vue from 'vue'
2+
import VueRouter from 'vue-router'
3+
import Home from '../views/Home.vue'
4+
5+
Vue.use(VueRouter)
6+
7+
const routes = [
8+
{
9+
path: '/',
10+
name: 'home',
11+
component: Home
12+
},
13+
{
14+
path: '/about',
15+
name: 'about',
16+
// route level code-splitting
17+
// this generates a separate chunk (about.[hash].js) for this route
18+
// which is lazy-loaded when the route is visited.
19+
<%_ if (doesCompile) { _%>
20+
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
21+
<%_ } else { _%>
22+
component: function () {
23+
return import(/* webpackChunkName: "about" */ '../views/About.vue')
24+
}
25+
<%_ } _%>
26+
}
27+
]
28+
29+
const router = new VueRouter({
30+
<%_ if (historyMode) { _%>
31+
mode: 'history',
32+
base: process.env.BASE_URL,
33+
<%_ } _%>
34+
routes
35+
})
36+
37+
export default router
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = (api, options = {}) => {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@vue/cli-plugin-router",
3+
"version": "4.0.0-alpha.3",
4+
"description": "router plugin for vue-cli",
5+
"main": "index.js",
6+
"repository": {
7+
"type": "git",
8+
"url": "git+https://github.com/vuejs/vue-cli.git",
9+
"directory": "packages/@vue/cli-plugin-router"
10+
},
11+
"keywords": [
12+
"vue",
13+
"cli",
14+
"router"
15+
],
16+
"author": "Evan You",
17+
"license": "MIT",
18+
"bugs": {
19+
"url": "https://github.com/vuejs/vue-cli/issues"
20+
},
21+
"homepage": "https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-plugin-router#readme",
22+
"publishConfig": {
23+
"access": "public"
24+
},
25+
"dependencies": {
26+
"@vue/cli-shared-utils": "^4.0.0-alpha.3"
27+
},
28+
"devDependencies": {
29+
"@vue/cli-test-utils": "^4.0.0-alpha.3"
30+
}
31+
}

0 commit comments

Comments
 (0)