feat: preliminary TS plugin imeplementation

This commit is contained in:
Evan You
2018-01-10 19:15:31 -05:00
parent 8aba87ff0b
commit 54a902d2ff
17 changed files with 528 additions and 5 deletions
@@ -0,0 +1,29 @@
module.exports = (api, options) => {
api.render('./template')
api.extendPackage({
scripts: {
lint: 'vue-cli-service lint'
}
})
if (options.classComponent) {
api.extendPackage({
devDependencies: {
'vue-class-component': '^6.0.0',
'vue-property-decorator': '^6.0.0'
}
})
}
// delete all js files that have a ts file of the same name
// TODO compat with PWA and test plugins
const jsRE = /\.js$/
api.postProcessFiles(files => {
for (const file in files) {
if (jsRE.test(file) && files[file.replace(jsRE, '.ts')]) {
delete files[file]
}
}
})
}
@@ -0,0 +1,70 @@
<%_ if (!rootOptions.router) { _%>
<template>
<div id="app">
<img src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script lang="ts">
<%_ if (!options.classComponent) { _%>
import Vue from 'vue';
import HelloWorld from './components/HelloWorld.vue';
export default Vue.extend({
name: 'app',
components: {
HelloWorld
}
});
<%_ } else { _%>
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from './components/HelloWorld.vue';
@Component({
components: {
HelloWorld,
},
})
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>
@@ -0,0 +1,59 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<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>
<br>
<li><a href="http://vuejs-templates.github.io/webpack/" target="_blank">Docs for This Template</a></li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
<li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
<li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
</ul>
</div>
</template>
<script lang="ts">
<%_ if (!options.classComponent) { _%>
import Vue from 'vue';
export default Vue.extend({
name: 'HelloWorld',
props: {
msg: String,
},
});
<%_ } else { _%>
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
export default class HelloWorld extends Vue {
@Prop() private msg: string;
}
<%_ } _%>
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
@@ -0,0 +1,20 @@
import Vue from 'vue';
import App from './App.vue';
<%_ if (rootOptions.router) { _%>
import router from './router';
<%_ } _%>
<%_ if (rootOptions.vuex) { _%>
import store from './store';
<%_ } _%>
Vue.config.productionTip = false;
new Vue({
<%_ if (rootOptions.router) { _%>
router,
<%_ } _%>
<%_ if (rootOptions.vuex) { _%>
store,
<%_ } _%>
render: h => h(App),
}).$mount('#app');
@@ -0,0 +1,23 @@
<%_ if (rootOptions.router) { _%>
import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: About
}
]
});
<%_ } _%>
@@ -0,0 +1,18 @@
<%_ if (rootOptions.vuex) { _%>
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
}
});
<%_ } _%>
@@ -0,0 +1,7 @@
<%_ if (rootOptions.router) { _%>
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<%_ } _%>
@@ -0,0 +1,32 @@
<%_ if (rootOptions.router) { _%>
<template>
<div class="home">
<img src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script lang="ts">
<%_ if (!options.classComponent) { _%>
import Vue from 'vue';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
export default Vue.extend({
name: 'home',
components: {
HelloWorld,
},
});
<%_ } else { _%>
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
@Component({
components: {
HelloWorld,
},
})
export default class Home extends Vue {}
<%_ } _%>
</script>
<%_ } _%>
@@ -0,0 +1,4 @@
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"strict": true,
"moduleResolution": "node",
<%_ if (options.classComponent) { _%>
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
<%_ } _%>
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
}
},
"include": [
"src/**/*.ts",
"src/**/*.vue"
],
"exclude": [
"node_modules"
]
}
@@ -0,0 +1,21 @@
{
"defaultSeverity": "warning",
"extends": [
"tslint:recommended"
],
"rules": {
"quotemark": [
true,
"single"
],
"indent": [
true
],
"interface-name": [
false
],
"arrow-parens": false,
// Pending fix for shorthand property names.
"object-literal-sort-keys": false
}
}
@@ -0,0 +1,69 @@
module.exports = api => {
api.chainWebpack(config => {
config.entry('app')
.clear()
.add('./src/main.ts')
config.resolve
.extensions
.merge(['.ts', '.tsx'])
config.module
.rule('ts')
.test(/\.tsx?$/)
.include
.add(api.resolve('src'))
.end()
.use('ts-loader')
.loader('ts-loader')
.options({
transpileOnly: true,
appendTsSuffixTo: [/\.vue$/]
})
config
.plugin('fork-ts-checker')
.use(require('fork-ts-checker-webpack-plugin'), [{
vue: true,
tslint: true,
formatter: 'codeframe'
}])
})
api.registerCommand('lint', {
descriptions: 'lint source files with TSLint',
usage: 'vue-cli-service lint [options] [...files]',
options: {
'--format': 'specify formatter (default: codeframe)',
'--no-fix': 'do not fix errors'
},
details: 'For more options, see https://palantir.github.io/tslint/usage/cli/'
}, (args) => {
const { run } = require('tslint/lib/runner')
return run({
files: args._ && args._.length ? args._ : ['src/**/*.ts'],
exclude: args.exclude || [],
fix: !args['no-fix'],
project: api.resolve('tsconfig.json'),
config: api.resolve('tslint.json'),
force: args.force,
format: args.format,
formattersDirectory: args['formatters-dir'],
init: args.init,
out: args.out,
outputAbsolutePaths: args['output-absolute-paths'],
rulesDirectory: args['rules-dir'],
test: args.test,
typeCheck: args['type-check']
}, {
log (m) { process.stdout.write(m) },
error (m) { process.stdout.write(m) }
}).then(code => {
process.exitCode = code
}).catch(err => {
console.error(err)
process.exitCode = 1
})
})
}
@@ -20,5 +20,15 @@
"homepage": "https://github.com/vuejs/vue-cli/packages/@vue/cli-plugin-typescript#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"fork-ts-checker-webpack-plugin": "^0.3.0",
"ts-loader": "^3.2.0",
"tslint": "^5.9.1",
"typescript": "^2.6.2"
},
"devDependencies": {
"vue-class-component": "^6.0.0",
"vue-property-decorator": "^6.0.0"
}
}
+3
View File
@@ -5,6 +5,7 @@ const execa = require('execa')
const resolve = require('resolve')
const inquirer = require('inquirer')
const Generator = require('./Generator')
const sortObject = require('./util/sortObject')
const installDeps = require('./util/installDeps')
const clearConsole = require('./util/clearConsole')
const PromptModuleAPI = require('./PromptModuleAPI')
@@ -189,6 +190,8 @@ module.exports = class Creator {
// { id: options } => [{ id, apply, options }]
resolvePlugins (rawPlugins) {
// ensure cli-service is invoked first
rawPlugins = sortObject(rawPlugins, ['@vue/cli-service'])
return Object.keys(rawPlugins).map(id => {
const module = resolve.sync(`${id}/generator`, { basedir: this.context })
return {
+2 -1
View File
@@ -64,7 +64,8 @@ module.exports = class GeneratorAPI {
for (const file of _files) {
const relativePath = path.relative(fileDir, file.path)
const content = renderFile(file.path, data, ejsOptions)
if (Buffer.isBuffer(content) || content.trim()) {
// only set file if it's not all whitespace, or is a Buffer (binary files)
if (Buffer.isBuffer(content) || /[^\s]/.test(content)) {
files[relativePath] = content
}
}
@@ -1,2 +1,22 @@
module.exports = cli => {
cli.injectFeature({
name: 'TypeScript',
value: 'ts',
short: 'TS'
})
cli.injectPrompt({
name: 'tsClassComponent',
when: answers => answers.features.includes('ts'),
type: 'confirm',
message: 'Use class-style component syntax?'
})
cli.onPromptComplete((answers, options) => {
if (answers.features.includes('ts')) {
options.plugins['@vue/cli-plugin-typescript'] = {
classComponent: answers.tsClassComponent
}
}
})
}
+115 -4
View File
@@ -984,6 +984,13 @@ aws4@^1.2.1, aws4@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
axios@^0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.17.1.tgz#2d8e3e5d0bdbd7327f91bc814f5c57660f81824d"
dependencies:
follow-redirects "^1.2.5"
is-buffer "^1.1.5"
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -2278,7 +2285,7 @@ commander@2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
commander@2.12.x, commander@^2.11.0, commander@^2.12.2, commander@^2.6.0, commander@^2.9.0, commander@~2.12.1:
commander@2.12.x, commander@^2.11.0, commander@^2.12.1, commander@^2.12.2, commander@^2.6.0, commander@^2.9.0, commander@~2.12.1:
version "2.12.2"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555"
@@ -3283,7 +3290,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
enhanced-resolve@^3.4.0:
enhanced-resolve@^3.0.0, enhanced-resolve@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
dependencies:
@@ -3524,13 +3531,19 @@ eslint-plugin-vue-libs@^2.1.0:
dependencies:
eslint-plugin-html "^4.0.1"
eslint-plugin-vue@^4.0.0, eslint-plugin-vue@^4.1.0:
eslint-plugin-vue@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-4.1.0.tgz#b5f65c04e1741fa93c97b9fe605ad9c55967dbbc"
dependencies:
require-all "^2.2.0"
vue-eslint-parser "^2.0.1"
eslint-plugin-vue@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-4.2.0.tgz#25fade387bf9a97377cf0e5cd17ef0d60ac9da57"
dependencies:
vue-eslint-parser "^2.0.1"
eslint-restricted-globals@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7"
@@ -4039,6 +4052,12 @@ flush-write-stream@^1.0.0:
inherits "^2.0.1"
readable-stream "^2.0.4"
follow-redirects@^1.2.5:
version "1.3.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.3.0.tgz#f684871fc116d2e329fda55ef67687f4fabc905c"
dependencies:
debug "^3.1.0"
for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -4057,6 +4076,21 @@ forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
fork-ts-checker-webpack-plugin@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-0.3.0.tgz#3c7339b981f9194c89f38c223258e0c702f99369"
dependencies:
babel-code-frame "^6.22.0"
chalk "^1.1.3"
chokidar "^1.7.0"
lodash.endswith "^4.2.1"
lodash.isfunction "^3.0.8"
lodash.isstring "^4.0.1"
lodash.startswith "^4.2.1"
minimatch "^3.0.4"
resolve "^1.5.0"
vue-parser "^1.1.5"
form-data@~2.1.1:
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
@@ -6041,6 +6075,10 @@ lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
lodash.endswith@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09"
lodash.get@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-3.7.0.tgz#3ce68ae2c91683b281cc5394128303cbf75e691f"
@@ -6052,6 +6090,14 @@ lodash.isarray@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
lodash.isfunction@^3.0.8:
version "3.0.8"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz#4db709fc81bc4a8fd7127a458a5346c5cdce2c6b"
lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -6060,6 +6106,10 @@ lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
lodash.startswith@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/lodash.startswith/-/lodash.startswith-4.2.1.tgz#c598c4adce188a27e53145731cdc6c0e7177600c"
lodash.template@^4.0.2, lodash.template@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
@@ -6976,7 +7026,7 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
parse5@^3.0.2:
parse5@^3.0.2, parse5@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
dependencies:
@@ -7759,6 +7809,10 @@ reduce-function-call@^1.0.1:
dependencies:
balanced-match "^0.4.2"
reflect-metadata@^0.1.10:
version "0.1.10"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a"
regenerate-unicode-properties@^5.1.1:
version "5.1.3"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-5.1.3.tgz#54f5891543468f36f2274b67c6bc4c033c27b308"
@@ -9003,6 +9057,15 @@ trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
ts-loader@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-3.2.0.tgz#23211922179b81f7448754b7fdfca45b8374a15a"
dependencies:
chalk "^2.3.0"
enhanced-resolve "^3.0.0"
loader-utils "^1.0.2"
semver "^5.0.1"
tsconfig@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7"
@@ -9012,6 +9075,33 @@ tsconfig@^7.0.0:
strip-bom "^3.0.0"
strip-json-comments "^2.0.0"
tslib@^1.8.0, tslib@^1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac"
tslint@^5.9.1:
version "5.9.1"
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae"
dependencies:
babel-code-frame "^6.22.0"
builtin-modules "^1.1.1"
chalk "^2.3.0"
commander "^2.12.1"
diff "^3.2.0"
glob "^7.1.1"
js-yaml "^3.7.0"
minimatch "^3.0.4"
resolve "^1.3.2"
semver "^5.3.0"
tslib "^1.8.0"
tsutils "^2.12.1"
tsutils@^2.12.1:
version "2.16.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.16.0.tgz#ad8e83f47bef4f7d24d173cc6cd180990c831105"
dependencies:
tslib "^1.8.1"
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@@ -9047,6 +9137,10 @@ typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
typescript@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
uglify-es@^3.3.4:
version "3.3.5"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.5.tgz#cf7e695da81999f85196b15e2978862f13212f88"
@@ -9361,6 +9455,10 @@ vm-browserify@0.0.4:
dependencies:
indexof "0.0.1"
vue-class-component@^6.0.0:
version "6.1.2"
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-6.1.2.tgz#87ac0265b0db71a3f49f10d90e4f69f9be9c2fbd"
vue-cli@^2.9.2:
version "2.9.2"
resolved "https://registry.yarnpkg.com/vue-cli/-/vue-cli-2.9.2.tgz#fb247c0f41c50c865e8d77caba18eb2b3936372c"
@@ -9434,6 +9532,19 @@ vue-loader@^13.7.0:
vue-style-loader "^3.0.0"
vue-template-es2015-compiler "^1.6.0"
vue-parser@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/vue-parser/-/vue-parser-1.1.5.tgz#726ca53ed679114518ebf8a22d7ab43da5d4ee25"
dependencies:
parse5 "^3.0.3"
vue-property-decorator@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/vue-property-decorator/-/vue-property-decorator-6.0.0.tgz#bb651b293542e31db0d24f36f4b0250ef08d8515"
dependencies:
reflect-metadata "^0.1.10"
vue-class-component "^6.0.0"
vue-router@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.1.tgz#d9b05ad9c7420ba0f626d6500d693e60092cc1e9"