https://github.com/Microsoft/TypeScript-Vue-Starter
A starter template for TypeScript and Vue with a detailed README describing how to use the two together.
https://github.com/Microsoft/TypeScript-Vue-Starter
Last synced: about 1 year ago
JSON representation
A starter template for TypeScript and Vue with a detailed README describing how to use the two together.
- Host: GitHub
- URL: https://github.com/Microsoft/TypeScript-Vue-Starter
- Owner: microsoft
- License: mit
- Archived: true
- Created: 2017-05-09T19:59:14.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2019-10-09T00:06:11.000Z (over 6 years ago)
- Last Synced: 2025-03-21T23:42:51.292Z (about 1 year ago)
- Language: JavaScript
- Size: 163 KB
- Stars: 4,446
- Watchers: 130
- Forks: 590
- Open Issues: 34
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-typescript - Microsoft - TypeScript-Vue-Starter
README
This repo is deprecated, it was created in the days before Vue shipped with TypeScript out of the box. Now the
best path to get started is through [the official CLI](https://cli.vuejs.org). We'll keep this repo around as
a useful archive.
---
# TypeScript Vue Starter
This quick start guide will teach you how to get [TypeScript](http://www.typescriptlang.org/) and [Vue](https://vuejs.org) working together.
This guide is flexible enough that any steps here can be used to integrate TypeScript into an existing Vue project.
# Before you begin
If you're new to Typescript and Vue, here are few resources to get you up and running:
## TypeScript
* [Up and Running with TypeScript](https://egghead.io/courses/up-and-running-with-typescript)
* [TypeScript 5 Minute Tutorial](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
* [Documentation](http://www.typescriptlang.org/docs/home.html)
* [TypeScript GitHub](https://github.com/Microsoft/TypeScript)
## Vue
* [Vuejs Guide](https://vuejs.org/v2/guide/)
* [Vuejs Tutorial](https://www.youtube.com/playlist?list=PL4cUxeGkcC9gQcYgjhBoeQH7wiAyZNrYa)
* [Build an App with Vue.js](https://scotch.io/tutorials/build-an-app-with-vue-js-a-lightweight-alternative-to-angularjs)
# Initialize your project
Let's create a new package.
```sh
mkdir typescript-vue-tutorial
cd typescript-vue-tutorial
```
Next, we'll scaffold our project in the following way:
```txt
typescript-vue-tutorial/
├─ dist/
└─ src/
└─ components/
```
TypeScript files will start out in your `src` folder, run through the TypeScript compiler, then webpack, and end up in a `bundle.js` file in `dist`.
Any components that we write will go in the `src/components` folder.
Let's scaffold this out:
```shell
mkdir src
cd src
mkdir components
cd ..
```
Webpack will eventually generate the `dist` directory for us.
# Initialize the project
Now we'll turn this folder into an npm package.
```shell
npm init
```
You'll be given a series of prompts.
You can use the defaults except for your entry point.
You can always go back and change these in the `package.json` file that's been generated for you.
# Install our dependencies
Ensure TypeScript, Webpack, Vue and the necessary loaders are installed.
```sh
npm install --save-dev typescript webpack webpack-cli ts-loader css-loader vue vue-loader vue-template-compiler
```
Webpack is a tool that will bundle your code and optionally all of its dependencies into a single `.js` file.
While you don't need to use a bundler like Webpack or Browserify, these tools will allow us to use `.vue` files which we'll cover in a bit.
We didn't need to [add `.d.ts` files](https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html), but if we were using a package which didn't ship declaration files, we'd need to install the appropriate `@types/` package.
[Read more about using definition files in our documentation](https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html).
# Add a TypeScript configuration file
You'll want to bring your TypeScript files together - both the code you'll be writing as well as any necessary declaration files.
To do this, you'll need to create a `tsconfig.json` which contains a list of your input files as well as all your compilation settings.
Simply create a new file in your project root named `tsconfig.json` and fill it with the following contents:
You can easily create `tsconfig.json` this command.
```
tsc --init
```
```json
{
"compilerOptions": {
"outDir": "./built/",
"sourceMap": true,
"strict": true,
"noImplicitReturns": true,
"module": "es2015",
"moduleResolution": "node",
"target": "es5"
},
"include": [
"./src/**/*"
]
}
```
Notice the `strict` flag is set to true.
At the very least, TypeScript's `noImplicitThis` flag will need to be turned on to leverage Vue's declaration files, but `strict` gives us that and more (like `noImplicitAny` and `strictNullChecks`).
We strongly recommend using TypeScript's stricter options for a better experience.
# Adding Webpack
We'll need to add a `webpack.config.js` to bundle our app.
```js
var path = require('path')
var webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this necessary.
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
}
// other vue-loader options go here
}
},
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/],
}
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
]
},
resolve: {
extensions: ['.ts', '.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
performance: {
hints: false
},
devtool: '#eval-source-map',
plugins: [
// make sure to include the plugin for the magic
new VueLoaderPlugin()
]
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
```
# Add a build script
Open up your `package.json` and add a script named `build` to run Webpack.
Your `"scripts"` field should look something like this:
```json
"scripts": {
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
```
Once we add an entry point, we'll be able to build by running
```sh
npm run build
```
and have builds get triggered on changes by running
```sh
npm run build -- --watch
```
# Create a basic project
Let's create the most bare-bones Vue & TypeScript example that we can try out.
First, create the file `./src/index.ts`:
```ts
// src/index.ts
import Vue from "vue";
let v = new Vue({
el: "#app",
template: `
Hello {{name}}!
Name:
`,
data: {
name: "World"
}
});
```
Let's check to see if everything is wired up correctly.
Create an `index.html` with the following content at your root:
```html
```
Now run `npm run build` and open up your `index.html` file in a browser.
You should see some text that says `Hello World!`.
Below that, you'll see a textbox.
If you change the content of the textbox, you'll notice how the text is synchronized between the two.
Congrats!
You've gotten TypeScript and Vue fully hooked up!
# Adding a component
As you've just seen, Vue has a very simple interface for when you need to accomplish simple tasks.
When our page only needed to communicate a bit of data between two elements, it took very little code.
For more complex tasks, Vue is flexible in that it supports breaking your application into *components*.
[Components](https://vuejs.org/v2/guide/components.html) are useful for separating the concerns of how entities are displayed to the user.
[Read up more on components from Vue's documentation.](https://vuejs.org/v2/guide/components.html)
A Vue component can be declared in the following manner:
```ts
// src/components/Hello.ts
import Vue from "vue";
export default Vue.extend({
template: `
Hello {{name}}{{exclamationMarks}}
-
+
`,
props: ['name', 'initialEnthusiasm'],
data() {
return {
enthusiasm: this.initialEnthusiasm,
}
},
methods: {
increment() { this.enthusiasm++; },
decrement() {
if (this.enthusiasm > 1) {
this.enthusiasm--;
}
},
},
computed: {
exclamationMarks(): string {
return Array(this.enthusiasm + 1).join('!');
}
}
});
```
This component has two buttons and some text.
When rendered, it takes an initial `name` and an `initialEnthusiasm` which is the number of exclamation marks we want to display.
When we hit the `+` button, it adds an exclamation mark to the end of the text.
Likewise, when we hit the `-` button, it removes an exclamation mark unless we're down to just one.
Our root Vue instance can consume it as follows:
```ts
// src/index.ts
import Vue from "vue";
import HelloComponent from "./components/Hello";
let v = new Vue({
el: "#app",
template: `
Name:
`,
data: { name: "World" },
components: {
HelloComponent
}
});
```
However, we'll note that it is fairly popular to use [Vue's *single file components*](https://vuejs.org/v2/guide/single-file-components.html).
Let's try writing the above as an SFC.
# Single File Components
When using Webpack or Browserify, Vue has plugins like [vue-loader](https://github.com/vuejs/vue-loader) and [vueify](https://www.npmjs.com/package/vueify) which allow you to author your components in HTML-like files.
These files, which end in a `.vue` extension, are single file components.
There are a few things that need to be put in place to use `.vue` files with TypeScript, but luckily we're already halfway there.
We already installed vue-loader earlier when we got our dev dependencies.
We also specified the `appendTsSuffixTo: [/\.vue$/],` option to ts-loader in our `webpack.config.js` file, which allows TypeScript to process the code extracted from a single file component.
One extra thing we'll have to do is tell TypeScript what `.vue` files will look like when they're imported.
We'll do this with a `vue-shims.d.ts` file:
```ts
// src/vue-shims.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
```
We don't need to import this file anywhere.
It's automatically included by TypeScript, and it tells it that anything imported that ends in `.vue` has the same shape of the Vue constructor itself.
What's left?
The editing experience!
One of the best features TypeScript gives us is its editor support.
To leverage that within `.vue` files, we recommend using [Visual Studio Code](https://code.visualstudio.com/) with the [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur) plugin for Vue.
Now, let's write an SFC!
```html
Hello {{name}}{{exclamationMarks}}
-
+
import Vue from "vue";
export default Vue.extend({
props: ['name', 'initialEnthusiasm'],
data() {
return {
enthusiasm: this.initialEnthusiasm,
}
},
methods: {
increment() { this.enthusiasm++; },
decrement() {
if (this.enthusiasm > 1) {
this.enthusiasm--;
}
},
},
computed: {
exclamationMarks(): string {
return Array(this.enthusiasm + 1).join('!');
}
}
});
.greeting {
font-size: 20px;
}
```
and let's import it for our root instance:
```ts
// src/index.ts
import Vue from "vue";
import HelloComponent from "./components/Hello.vue";
let v = new Vue({
el: "#app",
template: `
Name:
`,
data: { name: "World" },
components: {
HelloComponent
}
});
```
Notice a few things about our single-file component:
* We had to write `` to get it working with TypeScript.
* We had to import the component with the `.vue` extension in `index.ts`.
* We were able to write CSS isolated to our components in a `<style>` tag, which we couldn't do in our `.ts` components.
* We default-exported a call to `Vue.extend` (rather than the options bag itself).
If you don't write `Vue.extend`, Vetur will make it look like things are working correctly, but you'll get an error when you build your project.
Try running `npm run build` and open up `index.html` to see the result!
# Using decorators to define a component
Components can also be defined using [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html).
With the help of two additional packages, ([vue-class-component](https://github.com/vuejs/vue-class-component) and [vue-property-decorator](https://github.com/kaorun343/vue-property-decorator)), our components can be rewritten in the following manner:
```ts
import { Vue, Component, Prop } from "vue-property-decorator";
@Component
export default class HelloDecorator extends Vue {
@Prop() name!: string;
@Prop() initialEnthusiasm!: number;
enthusiasm = this.initialEnthusiasm;
increment() {
this.enthusiasm++;
}
decrement() {
if (this.enthusiasm > 1) {
this.enthusiasm--;
}
}
get exclamationMarks(): string {
return Array(this.enthusiasm + 1).join('!');
}
}
```
Instead of using `Vue.extend` to define our component, we create a class extending `Vue` and decorate it using the `@Component` decorator from the `vue-class-component` package (which was re-exported from the `vue-property-decorator` package).
Properties are defined by prefixing instance variables with the `@Prop()` decorator from the `vue-property-decorator` package.
Because the `--strictPropertyInitialization` option is on, we need to tell TypeScript that Vue will initialize our properties by appending a `!` to them.
This tells TypeScript "hey, relax, someone else is going to assign this property a value."
Regular instance variables, such as `enthusiasm` in our example, are automatically made available for data binding to the template, just as if they had been defined in the `data` field.
Note that all variables must be set to a value other than `undefined` for the binding to work.
Similarly, methods such as `increment` are treated as if they had been written in the `methods` field, and are automatically made available for the template.
Finally, computed properties like `exclamationMarks` are simply written as `get` accessors.
# What next?
You can [try out this application by cloning it from GitHub](https://github.com/DanielRosenwasser/typescript-vue-tutorial).
Once you feel like you've got a handle on that, you can try out a sample [TodoMVC-style app written in TypeScript and Vue](https://github.com/DanielRosenwasser/typescript-vue-todomvc).
This TodoMVC-style sample features routing through [vue-router](https://github.com/vuejs/vue-router) so that your application can show different views depending on the current URL.
You may also want to look into [Vuex](https://github.com/vuejs/vuex) if you're looking for [Redux](http://redux.js.org/)-style state management.