Skip to content

Commit 1869aa2

Browse files
committed
feat: Generator now supports template inheritance
1 parent b878767 commit 1869aa2

File tree

14 files changed

+96
-124
lines changed

14 files changed

+96
-124
lines changed

Diff for: packages/@vue/cli-plugin-typescript/__tests__/tsPluginE2e.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ test('cypress', async () => {
1313
})
1414

1515
test('cypress with router', async () => {
16-
const project = await create('ts-e2e-cypress', {
16+
const project = await create('ts-e2e-cypress-router', {
1717
router: true,
1818
plugins: {
1919
'@vue/cli-plugin-typescript': {},
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
<%_ if (!rootOptions.router) { _%>
2-
<template>
3-
<div id="app">
4-
<img src="./assets/logo.png">
5-
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
6-
</div>
7-
</template>
1+
---
2+
extend: '@vue/cli-service/generator/template/src/App.vue'
3+
replace:
4+
- !!js/regexp /Welcome to Your Vue\.js App/
5+
- !!js/regexp /<script>[^]*?<\/script>/
6+
---
87
8+
<%# REPLACE %>
9+
Welcome to Your Vue.js + TypeScript App
10+
<%# END_REPLACE %>
11+
12+
<%# REPLACE %>
913
<script lang="ts">
10-
<%_ if (!options.classComponent) { _%>
14+
<%_ if (!options.classComponent) { _%>
1115
import Vue from 'vue';
1216
import HelloWorld from './components/HelloWorld.vue';
1317
@@ -17,7 +21,7 @@ export default Vue.extend({
1721
HelloWorld
1822
}
1923
});
20-
<%_ } else { _%>
24+
<%_ } else { _%>
2125
import { Component, Vue } from 'vue-property-decorator';
2226
import HelloWorld from './components/HelloWorld.vue';
2327
@@ -27,44 +31,6 @@ import HelloWorld from './components/HelloWorld.vue';
2731
},
2832
})
2933
export default class App extends Vue {}
30-
<%_ } _%>
31-
</script>
32-
<%_ } else { _%>
33-
<template>
34-
<div id="app">
35-
<div id="nav">
36-
<router-link to="/">Home</router-link> |
37-
<router-link to="/about">About</router-link>
38-
</div>
39-
<router-view/>
40-
</div>
41-
</template>
42-
<%_ } _%>
43-
44-
<style>
45-
#app {
46-
font-family: 'Avenir', Helvetica, Arial, sans-serif;
47-
-webkit-font-smoothing: antialiased;
48-
-moz-osx-font-smoothing: grayscale;
49-
text-align: center;
50-
color: #2c3e50;
51-
<%_ if (!rootOptions.router) { _%>
52-
margin-top: 60px;
53-
<%_ } _%>
54-
}
55-
<%_ if (rootOptions.router) { _%>
56-
57-
#nav {
58-
padding: 30px;
59-
}
60-
61-
#nav a {
62-
font-weight: bold;
63-
color: #2c3e50;
64-
}
65-
66-
#nav a.router-link-exact-active {
67-
color: #42b983;
68-
}
6934
<%_ } _%>
70-
</style>
35+
</script>
36+
<%# END_REPLACE %>
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,7 @@
1-
<template>
2-
<div class="hello">
3-
<h1>{{ msg }}</h1>
4-
<p>
5-
For guide and recipes on how to configure / customize this project,<br>
6-
check out the
7-
<a href="https://github.com/vuejs/vue-cli/tree/dev/docs" target="_blank">vue-cli documentation</a>.
8-
</p>
9-
<h3>Installed CLI Plugins</h3>
10-
<ul>
11-
<%_ for (plugin of plugins) { _%>
12-
<li><a href="<%- plugin.link %>" target="_blank"><%- plugin.name %></a></li>
13-
<%_ } _%>
14-
</ul>
15-
<h3>Essential Links</h3>
16-
<ul>
17-
<li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
18-
<li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
19-
<li><a href="https://chat.vuejs.org" target="_blank">Community Chat</a></li>
20-
<li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
21-
</ul>
22-
<h3>Ecosystem</h3>
23-
<ul>
24-
<li><a href="https://router.vuejs.org/en/essentials/getting-started.html" target="_blank">vue-router</a></li>
25-
<li><a href="https://vuex.vuejs.org/en/intro.html" target="_blank">vuex</a></li>
26-
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank">vue-devtools</a></li>
27-
<li><a href="https://vue-loader.vuejs.org/en" target="_blank">vue-loader</a></li>
28-
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
29-
</ul>
30-
</div>
31-
</template>
32-
1+
---
2+
extend: '@vue/cli-service/generator/template/src/components/HelloWorld.vue'
3+
replace: !!js/regexp /<script>[^]*?<\/script>/
4+
---
335
<script lang="ts">
346
<%_ if (!options.classComponent) { _%>
357
import Vue from 'vue';
@@ -49,21 +21,3 @@ export default class HelloWorld extends Vue {
4921
}
5022
<%_ } _%>
5123
</script>
52-
53-
<!-- Add "scoped" attribute to limit CSS to this component only -->
54-
<style scoped>
55-
h3 {
56-
margin: 40px 0 0;
57-
}
58-
ul {
59-
list-style-type: none;
60-
padding: 0;
61-
}
62-
li {
63-
display: inline-block;
64-
margin: 0 10px;
65-
}
66-
a {
67-
color: #42b983;
68-
}
69-
</style>

Diff for: packages/@vue/cli-plugin-typescript/generator/template/src/views/Home.vue

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
<%_ if (rootOptions.router) { _%>
2-
<template>
3-
<div class="home">
4-
<img src="../assets/logo.png">
5-
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
6-
</div>
7-
</template>
1+
---
2+
extend: '@vue/cli-service/generator/template/src/views/Home.vue'
3+
replace:
4+
- !!js/regexp /Welcome to Your Vue\.js App/
5+
- !!js/regexp /<script>[^]*?<\/script>/
6+
---
87
8+
<%# REPLACE %>
9+
Welcome to Your Vue.js + TypeScript App
10+
<%# END_REPLACE %>
11+
12+
<%# REPLACE %>
913
<script lang="ts">
1014
<%_ if (!options.classComponent) { _%>
1115
import Vue from 'vue';
@@ -29,4 +33,4 @@ import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
2933
export default class Home extends Vue {}
3034
<%_ } _%>
3135
</script>
32-
<%_ } _%>
36+
<%# END_REPLACE %>

Diff for: packages/@vue/cli-service/generator/template/public/index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
<meta http-equiv="X-UA-Compatible" content="IE=edge">
66
<meta name="viewport" content="width=device-width,initial-scale=1.0">
77
<link rel="shortcut icon" href="<%%= webpackConfig.output.publicPath %%>favicon.ico">
8-
<title><%= options.projectName %></title>
8+
<title><%= rootOptions.projectName %></title>
99
</head>
1010
<body>
1111
<noscript>
12-
<strong>We're sorry but <%= options.projectName %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
12+
<strong>We're sorry but <%= rootOptions.projectName %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
1313
</noscript>
1414
<div id="app"></div>
1515
<!-- built files will be auto injected -->

Diff for: packages/@vue/cli-service/generator/template/src/App.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<%_ if (!options.router) { _%>
1+
<%_ if (!rootOptions.router) { _%>
22
<template>
33
<div id="app">
44
<img src="./assets/logo.png">
@@ -35,11 +35,11 @@ export default {
3535
-moz-osx-font-smoothing: grayscale;
3636
text-align: center;
3737
color: #2c3e50;
38-
<%_ if (!options.router) { _%>
38+
<%_ if (!rootOptions.router) { _%>
3939
margin-top: 60px;
4040
<%_ } _%>
4141
}
42-
<%_ if (options.router) { _%>
42+
<%_ if (rootOptions.router) { _%>
4343

4444
#nav {
4545
padding: 30px;

Diff for: packages/@vue/cli-service/generator/template/src/main.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import Vue from 'vue'
22
import App from './App.vue'
3-
<%_ if (options.router) { _%>
3+
<%_ if (rootOptions.router) { _%>
44
import router from './router'
55
<%_ } _%>
6-
<%_ if (options.vuex) { _%>
6+
<%_ if (rootOptions.vuex) { _%>
77
import store from './store'
88
<%_ } _%>
99

1010
Vue.config.productionTip = false
1111

1212
new Vue({
13-
<%_ if (options.router) { _%>
13+
<%_ if (rootOptions.router) { _%>
1414
router,
1515
<%_ } _%>
16-
<%_ if (options.vuex) { _%>
16+
<%_ if (rootOptions.vuex) { _%>
1717
store,
1818
<%_ } _%>
1919
render: h => h(App)

Diff for: packages/@vue/cli-service/generator/template/src/router.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<%_ if (options.router) { _%>
1+
<%_ if (rootOptions.router) { _%>
22
import Vue from 'vue'
33
import Router from 'vue-router'
44
import Home from './views/Home.vue'

Diff for: packages/@vue/cli-service/generator/template/src/store.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<%_ if (options.vuex) { _%>
1+
<%_ if (rootOptions.vuex) { _%>
22
import Vue from 'vue'
33
import Vuex from 'vuex'
44

Diff for: packages/@vue/cli-service/generator/template/src/views/About.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<%_ if (options.router) { _%>
1+
<%_ if (rootOptions.router) { _%>
22
<template>
33
<div class="about">
44
<h1>This is an about page</h1>

Diff for: packages/@vue/cli-service/generator/template/src/views/Home.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<%_ if (options.router) { _%>
1+
<%_ if (rootOptions.router) { _%>
22
<template>
33
<div class="home">
44
<img src="../assets/logo.png">

Diff for: packages/@vue/cli/lib/GeneratorAPI.js

+37-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const ejs = require('ejs')
33
const path = require('path')
44
const globby = require('globby')
55
const isBinary = require('isbinaryfile')
6+
const yaml = require('yaml-front-matter')
67
const mergeDeps = require('./util/mergeDeps')
78

89
const isString = val => typeof val === 'string'
@@ -207,11 +208,46 @@ function extractCallDir () {
207208
return path.dirname(fileName)
208209
}
209210

211+
const replaceBlockRE = /<%# REPLACE %>([^]*?)<%# END_REPLACE %>/g
212+
210213
function renderFile (name, data, ejsOptions) {
211214
if (isBinary.sync(name)) {
212215
return fs.readFileSync(name) // return buffer
213216
}
214-
return ejs.render(fs.readFileSync(name, 'utf-8'), data, ejsOptions)
217+
const template = fs.readFileSync(name, 'utf-8')
218+
219+
// custom template inheritance via yaml front matter.
220+
// ---
221+
// extend: 'source-file'
222+
// replace: !!js/regexp /some-regex/
223+
// OR
224+
// replace:
225+
// - !!js/regexp /foo/
226+
// - !!js/regexp /bar/
227+
// ---
228+
const parsed = yaml.loadFront(template)
229+
const content = parsed.__content
230+
let finalTemplate = content.trim() + `\n`
231+
if (parsed.extend) {
232+
finalTemplate = fs.readFileSync(require.resolve(parsed.extend), 'utf-8')
233+
if (parsed.replace) {
234+
if (Array.isArray(parsed.replace)) {
235+
const replaceMatch = content.match(replaceBlockRE)
236+
if (replaceMatch) {
237+
const replaces = replaceMatch.map(m => {
238+
return m.replace(replaceBlockRE, '$1').trim()
239+
})
240+
parsed.replace.forEach((r, i) => {
241+
finalTemplate = finalTemplate.replace(r, replaces[i])
242+
})
243+
}
244+
} else {
245+
finalTemplate = finalTemplate.replace(parsed.replace, content.trim())
246+
}
247+
}
248+
}
249+
250+
return ejs.render(finalTemplate, data, ejsOptions)
215251
}
216252

217253
module.exports = GeneratorAPI

Diff for: packages/@vue/cli/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
"resolve": "^1.5.0",
5050
"rimraf": "^2.6.2",
5151
"semver": "^5.4.1",
52-
"slash": "^1.0.0"
52+
"slash": "^1.0.0",
53+
"yaml-front-matter": "^3.4.1"
5354
},
5455
"engines": {
5556
"node": ">=8"

Diff for: yarn.lock

+12-1
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,10 @@ command-join@^2.0.0:
20672067
version "2.0.0"
20682068
resolved "https://registry.yarnpkg.com/command-join/-/command-join-2.0.0.tgz#52e8b984f4872d952ff1bdc8b98397d27c7144cf"
20692069

2070+
2071+
version "1.0.0"
2072+
resolved "https://registry.yarnpkg.com/commander/-/commander-1.0.0.tgz#5e6a88e7070ff5908836ead19169548c30f90bcd"
2073+
20702074
20712075
version "2.11.0"
20722076
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
@@ -5697,7 +5701,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
56975701
version "3.0.2"
56985702
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
56995703

5700-
js-yaml@^3.10.0, js-yaml@^3.4.3, js-yaml@^3.7.0, js-yaml@^3.8.1, js-yaml@^3.9.0, js-yaml@^3.9.1:
5704+
js-yaml@^3.10.0, js-yaml@^3.4.3, js-yaml@^3.5.2, js-yaml@^3.7.0, js-yaml@^3.8.1, js-yaml@^3.9.0, js-yaml@^3.9.1:
57015705
version "3.10.0"
57025706
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc"
57035707
dependencies:
@@ -10411,6 +10415,13 @@ yallist@^2.1.2:
1041110415
version "2.1.2"
1041210416
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
1041310417

10418+
yaml-front-matter@^3.4.1:
10419+
version "3.4.1"
10420+
resolved "https://registry.yarnpkg.com/yaml-front-matter/-/yaml-front-matter-3.4.1.tgz#e52e84fea6983b93755e9b1564dba989b006b5a5"
10421+
dependencies:
10422+
commander "1.0.0"
10423+
js-yaml "^3.5.2"
10424+
1041410425
1041510426
version "0.0.8"
1041610427
resolved "https://registry.yarnpkg.com/yaml-js/-/yaml-js-0.0.8.tgz#87cfa5a9613f48e26005420d6a8ee0da6fe8daec"

0 commit comments

Comments
 (0)