Skip to content

Commit

Permalink
feat: Generator now supports template inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Mar 3, 2018
1 parent b878767 commit 1869aa2
Show file tree
Hide file tree
Showing 14 changed files with 96 additions and 124 deletions.
Expand Up @@ -13,7 +13,7 @@ test('cypress', async () => {
})

test('cypress with router', async () => {
const project = await create('ts-e2e-cypress', {
const project = await create('ts-e2e-cypress-router', {
router: true,
plugins: {
'@vue/cli-plugin-typescript': {},
Expand Down
64 changes: 15 additions & 49 deletions packages/@vue/cli-plugin-typescript/generator/template/src/App.vue
@@ -1,13 +1,17 @@
<%_ if (!rootOptions.router) { _%>
<template>
<div id="app">
<img src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</div>
</template>
---
extend: '@vue/cli-service/generator/template/src/App.vue'
replace:
- !!js/regexp /Welcome to Your Vue\.js App/
- !!js/regexp /<script>[^]*?<\/script>/
---
<%# REPLACE %>
Welcome to Your Vue.js + TypeScript App
<%# END_REPLACE %>
<%# REPLACE %>
<script lang="ts">
<%_ if (!options.classComponent) { _%>
<%_ if (!options.classComponent) { _%>
import Vue from 'vue';
import HelloWorld from './components/HelloWorld.vue';
Expand All @@ -17,7 +21,7 @@ export default Vue.extend({
HelloWorld
}
});
<%_ } else { _%>
<%_ } else { _%>
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from './components/HelloWorld.vue';
Expand All @@ -27,44 +31,6 @@ import HelloWorld from './components/HelloWorld.vue';
},
})
export default class App extends Vue {}
<%_ } _%>
</script>
<%_ } else { _%>
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<%_ } _%>

<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
<%_ if (!rootOptions.router) { _%>
margin-top: 60px;
<%_ } _%>
}
<%_ if (rootOptions.router) { _%>
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
<%_ } _%>
</style>
</script>
<%# END_REPLACE %>
@@ -1,35 +1,7 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://github.com/vuejs/vue-cli/tree/dev/docs" target="_blank">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<%_ for (plugin of plugins) { _%>
<li><a href="<%- plugin.link %>" target="_blank"><%- plugin.name %></a></li>
<%_ } _%>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org/en/essentials/getting-started.html" target="_blank">vue-router</a></li>
<li><a href="https://vuex.vuejs.org/en/intro.html" target="_blank">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org/en" target="_blank">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
</ul>
</div>
</template>

---
extend: '@vue/cli-service/generator/template/src/components/HelloWorld.vue'
replace: !!js/regexp /<script>[^]*?<\/script>/
---
<script lang="ts">
<%_ if (!options.classComponent) { _%>
import Vue from 'vue';
Expand All @@ -49,21 +21,3 @@ export default class HelloWorld extends Vue {
}
<%_ } _%>
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
@@ -1,11 +1,15 @@
<%_ if (rootOptions.router) { _%>
<template>
<div class="home">
<img src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</div>
</template>
---
extend: '@vue/cli-service/generator/template/src/views/Home.vue'
replace:
- !!js/regexp /Welcome to Your Vue\.js App/
- !!js/regexp /<script>[^]*?<\/script>/
---
<%# REPLACE %>
Welcome to Your Vue.js + TypeScript App
<%# END_REPLACE %>
<%# REPLACE %>
<script lang="ts">
<%_ if (!options.classComponent) { _%>
import Vue from 'vue';
Expand All @@ -29,4 +33,4 @@ import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
export default class Home extends Vue {}
<%_ } _%>
</script>
<%_ } _%>
<%# END_REPLACE %>
Expand Up @@ -5,11 +5,11 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="shortcut icon" href="<%%= webpackConfig.output.publicPath %%>favicon.ico">
<title><%= options.projectName %></title>
<title><%= rootOptions.projectName %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= options.projectName %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
<strong>We're sorry but <%= rootOptions.projectName %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
Expand Down
6 changes: 3 additions & 3 deletions packages/@vue/cli-service/generator/template/src/App.vue
@@ -1,4 +1,4 @@
<%_ if (!options.router) { _%>
<%_ if (!rootOptions.router) { _%>
<template>
<div id="app">
<img src="./assets/logo.png">
Expand Down Expand Up @@ -35,11 +35,11 @@ export default {
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
<%_ if (!options.router) { _%>
<%_ if (!rootOptions.router) { _%>
margin-top: 60px;
<%_ } _%>
}
<%_ if (options.router) { _%>
<%_ if (rootOptions.router) { _%>
#nav {
padding: 30px;
Expand Down
8 changes: 4 additions & 4 deletions packages/@vue/cli-service/generator/template/src/main.js
@@ -1,19 +1,19 @@
import Vue from 'vue'
import App from './App.vue'
<%_ if (options.router) { _%>
<%_ if (rootOptions.router) { _%>
import router from './router'
<%_ } _%>
<%_ if (options.vuex) { _%>
<%_ if (rootOptions.vuex) { _%>
import store from './store'
<%_ } _%>

Vue.config.productionTip = false

new Vue({
<%_ if (options.router) { _%>
<%_ if (rootOptions.router) { _%>
router,
<%_ } _%>
<%_ if (options.vuex) { _%>
<%_ if (rootOptions.vuex) { _%>
store,
<%_ } _%>
render: h => h(App)
Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/cli-service/generator/template/src/router.js
@@ -1,4 +1,4 @@
<%_ if (options.router) { _%>
<%_ if (rootOptions.router) { _%>
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/cli-service/generator/template/src/store.js
@@ -1,4 +1,4 @@
<%_ if (options.vuex) { _%>
<%_ if (rootOptions.vuex) { _%>
import Vue from 'vue'
import Vuex from 'vuex'

Expand Down
@@ -1,4 +1,4 @@
<%_ if (options.router) { _%>
<%_ if (rootOptions.router) { _%>
<template>
<div class="about">
<h1>This is an about page</h1>
Expand Down
@@ -1,4 +1,4 @@
<%_ if (options.router) { _%>
<%_ if (rootOptions.router) { _%>
<template>
<div class="home">
<img src="../assets/logo.png">
Expand Down
38 changes: 37 additions & 1 deletion packages/@vue/cli/lib/GeneratorAPI.js
Expand Up @@ -3,6 +3,7 @@ const ejs = require('ejs')
const path = require('path')
const globby = require('globby')
const isBinary = require('isbinaryfile')
const yaml = require('yaml-front-matter')
const mergeDeps = require('./util/mergeDeps')

const isString = val => typeof val === 'string'
Expand Down Expand Up @@ -207,11 +208,46 @@ function extractCallDir () {
return path.dirname(fileName)
}

const replaceBlockRE = /<%# REPLACE %>([^]*?)<%# END_REPLACE %>/g

function renderFile (name, data, ejsOptions) {
if (isBinary.sync(name)) {
return fs.readFileSync(name) // return buffer
}
return ejs.render(fs.readFileSync(name, 'utf-8'), data, ejsOptions)
const template = fs.readFileSync(name, 'utf-8')

// custom template inheritance via yaml front matter.
// ---
// extend: 'source-file'
// replace: !!js/regexp /some-regex/
// OR
// replace:
// - !!js/regexp /foo/
// - !!js/regexp /bar/
// ---
const parsed = yaml.loadFront(template)
const content = parsed.__content
let finalTemplate = content.trim() + `\n`
if (parsed.extend) {
finalTemplate = fs.readFileSync(require.resolve(parsed.extend), 'utf-8')
if (parsed.replace) {
if (Array.isArray(parsed.replace)) {
const replaceMatch = content.match(replaceBlockRE)
if (replaceMatch) {
const replaces = replaceMatch.map(m => {
return m.replace(replaceBlockRE, '$1').trim()
})
parsed.replace.forEach((r, i) => {
finalTemplate = finalTemplate.replace(r, replaces[i])
})
}
} else {
finalTemplate = finalTemplate.replace(parsed.replace, content.trim())
}
}
}

return ejs.render(finalTemplate, data, ejsOptions)
}

module.exports = GeneratorAPI
3 changes: 2 additions & 1 deletion packages/@vue/cli/package.json
Expand Up @@ -49,7 +49,8 @@
"resolve": "^1.5.0",
"rimraf": "^2.6.2",
"semver": "^5.4.1",
"slash": "^1.0.0"
"slash": "^1.0.0",
"yaml-front-matter": "^3.4.1"
},
"engines": {
"node": ">=8"
Expand Down
13 changes: 12 additions & 1 deletion yarn.lock
Expand Up @@ -2067,6 +2067,10 @@ command-join@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/command-join/-/command-join-2.0.0.tgz#52e8b984f4872d952ff1bdc8b98397d27c7144cf"

commander@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-1.0.0.tgz#5e6a88e7070ff5908836ead19169548c30f90bcd"

commander@2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
Expand Down Expand Up @@ -5697,7 +5701,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"

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:
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:
version "3.10.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc"
dependencies:
Expand Down Expand Up @@ -10411,6 +10415,13 @@ yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"

yaml-front-matter@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/yaml-front-matter/-/yaml-front-matter-3.4.1.tgz#e52e84fea6983b93755e9b1564dba989b006b5a5"
dependencies:
commander "1.0.0"
js-yaml "^3.5.2"

yaml-js@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/yaml-js/-/yaml-js-0.0.8.tgz#87cfa5a9613f48e26005420d6a8ee0da6fe8daec"
Expand Down

0 comments on commit 1869aa2

Please sign in to comment.