feat(ts): typescript examples + improve vue-app typings (#4695)

This commit is contained in:
Kevin Marrec 2019-01-06 10:07:17 +01:00 committed by Pooya Parsa
parent 3ccfcedb65
commit b38e0aac43
28 changed files with 206 additions and 140 deletions

View File

@ -0,0 +1,3 @@
# TypeScript with Vuex example
https://nuxtjs.org/examples/typescript-vuex

View File

@ -13,18 +13,14 @@
</template> </template>
<script lang="ts"> <script lang="ts">
// PLEASE NOTE import { Vue, Component, Prop } from 'vue-property-decorator'
// All "Nuxt Class Components" require at minimum a script tag that exports a default object
import Vue from 'vue'
import Component from 'nuxt-class-component'
import { Prop } from 'vue-property-decorator'
import { namespace } from 'vuex-class' import { namespace } from 'vuex-class'
import * as people from '~/store/modules/people' import * as people from '~/store/modules/people'
const People = namespace(people.name) const People = namespace(people.name)
@Component({}) @Component
export default class Card extends Vue { export default class Card extends Vue {
@Prop() person @Prop() person
@People.Action select @People.Action select

View File

@ -0,0 +1,12 @@
<template>
<div class="container">
<Nuxt />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class DefaultLayout extends Vue {}
</script>

View File

@ -1,23 +1,15 @@
export default { const config = {
env: {
baseUrl: process.env.BASE_URL || 'http://localhost:3000'
},
head: { head: {
title: 'starter', title: 'starter',
meta: [ meta: [
{ charset: 'utf-8' }, { charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'Nuxt.js project' } { hid: 'description', name: 'description', content: 'Nuxt TS project' }
], ],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
}, },
/*
** Customize the progress-bar color
*/
loading: { color: '#3B8070' }, loading: { color: '#3B8070' },
/* css: ['tachyons/css/tachyons.min.css', '~/assets/css/main.css']
** Build configuration
*/
css: ['tachyons/css/tachyons.min.css', '~/assets/css/main.css'],
modules: ['~/modules/typescript']
} }
export default config

View File

@ -0,0 +1,22 @@
{
"version": "1.0.0",
"private": true,
"dependencies": {
"axios": "^0.18.0",
"nuxt-ts-edge": "latest",
"tachyons": "^4.11.1",
"vue-property-decorator": "^7.2.0",
"vuex-class": "^0.3.1"
},
"scripts": {
"dev": "nuxt-ts",
"build": "nuxt-ts build",
"start": "nuxt-ts start",
"generate": "nuxt-ts generate",
"lint": "tslint --project ."
},
"devDependencies": {
"@types/node": "^10.12.18",
"tslint-config-standard": "^8.0.1"
}
}

View File

@ -0,0 +1,39 @@
<template>
<section class="pa4">
<div class="bg-white-90 pa4">
<div class="f1">
Nuxt TypeScript Starter
</div>
<div class="f3">
Selected Person: {{ selectedPerson.first_name }} {{ selectedPerson.last_name }}
</div>
{{ selected }}
</div>
<div class="flex flex-wrap ph2 justify-between bg-white-80">
<div v-for="person in people" :key="person.id">
<Card :person="person" />
</div>
</div>
</section>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Card from '~/components/Card.vue'
import { namespace } from 'vuex-class'
import * as people from '~/store/modules/people'
const People = namespace(people.name)
@Component({
components: {
Card
}
})
export default class IndexPage extends Vue {
@People.State selected
@People.State people
@People.Getter selectedPerson
}
</script>

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -11,11 +11,7 @@ import * as people from './modules/people'
// action: Sync or async operations that commit mutations // action: Sync or async operations that commit mutations
// mutations: Modify the state // mutations: Modify the state
interface ModulesStates { export type RootState = root.State
people: people.State
}
export type RootState = root.State & ModulesStates
const createStore = () => { const createStore = () => {
return new Vuex.Store({ return new Vuex.Store({

View File

@ -52,20 +52,20 @@ export const getters: GetterTree<State, RootState> = {
} }
export interface Actions<S, R> extends ActionTree<S, R> { export interface Actions<S, R> extends ActionTree<S, R> {
select(context: ActionContext<S, R>, id: number): void select (context: ActionContext<S, R>, id: number): void
} }
export const actions: Actions<State, RootState> = { export const actions: Actions<State, RootState> = {
select({ commit }, id: number) { select ({ commit }, id: number) {
commit(types.SELECT, id) commit(types.SELECT, id)
} }
} }
export const mutations: MutationTree<State> = { export const mutations: MutationTree<State> = {
[types.SELECT](state, id: number) { [types.SELECT] (state, id: number) {
state.selected = id state.selected = id
}, },
[types.SET](state, people: Person[]) { [types.SET] (state, people: Person[]) {
state.people = people state.people = people
} }
} }

View File

@ -1,5 +1,5 @@
import { GetterTree, ActionContext, ActionTree, MutationTree } from 'vuex' import { GetterTree, ActionContext, ActionTree, MutationTree } from 'vuex'
import axios from '~/plugins/axios' import axios from 'axios'
import { RootState } from 'store' import { RootState } from 'store'
import * as people from './modules/people' import * as people from './modules/people'
@ -12,12 +12,12 @@ export const state = (): State => ({})
export const getters: GetterTree<State, RootState> = {} export const getters: GetterTree<State, RootState> = {}
export interface Actions<S, R> extends ActionTree<S, R> { export interface Actions<S, R> extends ActionTree<S, R> {
nuxtServerInit(context: ActionContext<S, R>): void nuxtServerInit (context: ActionContext<S, R>): void
} }
export const actions: Actions<State, RootState> = { export const actions: Actions<State, RootState> = {
async nuxtServerInit({ commit }) { async nuxtServerInit ({ commit }) {
const response = await axios.get('/random-data.json') const response = await axios.get('/random-data.json', { proxy: { host: '127.0.0.1', port: 3000 } })
const staticPeople = response.data.slice(0, 10) const staticPeople = response.data.slice(0, 10)
commit(`${people.name}/${people.types.SET}`, staticPeople, { root: true }) commit(`${people.name}/${people.types.SET}`, staticPeople, { root: true })
} }

View File

@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"moduleResolution": "node",
"lib": ["es2015", "dom"],
"esModuleInterop": true,
"experimentalDecorators": true,
"allowJs": true,
"sourceMap": true,
"strict": true,
"allowSyntheticDefaultImports": true,
"noImplicitAny": false,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": true,
"baseUrl": ".",
"paths": {
"~/*": ["./*"]
},
"types": [
"@types/node",
"@nuxt/vue-app-edge"
]
}
}

View File

@ -0,0 +1,9 @@
{
"defaultSeverity": "error",
"extends": [
"tslint-config-standard"
],
"rules": {
"prefer-const": true
}
}

View File

@ -1,9 +0,0 @@
module.exports = {
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true
}
}
}

View File

@ -1,3 +1,3 @@
# Using typescript within nuxt.js # TypeScript example
https://github.com/johnlindquist/nuxt-typescript-starter/ https://nuxtjs.org/examples/typescript

View File

@ -0,0 +1,14 @@
<template>
<div>
{{ message }}
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
message: string = 'Hello world !'
}
</script>

View File

@ -1,5 +0,0 @@
<template>
<div class="container">
<Nuxt />
</div>
</template>

View File

@ -1,30 +0,0 @@
export default function () {
// Add .ts extension for store, middleware and more
this.nuxt.options.extensions.push('ts')
// Extend build
this.extendBuild((config) => {
const tsLoader = {
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
},
exclude: [
/dist/,
/\.temp/
]
}
// Add TypeScript loader
config.module.rules.push(
Object.assign(
{
test: /((client|server)\.js)|(\.tsx?)$/
},
tsLoader
)
)
// Add .ts extension in webpack resolve
if (config.resolve.extensions.indexOf('.ts') === -1) {
config.resolve.extensions.push('.ts')
}
})
}

View File

@ -0,0 +1,3 @@
export default {
plugins: ['~/plugins/hello']
}

View File

@ -1,22 +1,19 @@
{ {
"version": "1.0.1", "version": "1.0.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"axios": "^0.18.0", "nuxt-ts-edge": "latest",
"nuxt-class-component": "^1.1.3", "vue-property-decorator": "^7.2.0"
"nuxt-edge": "latest",
"tachyons": "^4.9.1",
"vue-property-decorator": "^7.2.0",
"vuex-class": "^0.3.1"
}, },
"scripts": { "scripts": {
"dev": "nuxt", "dev": "nuxt-ts",
"build": "nuxt build", "build": "nuxt-ts build",
"start": "nuxt start", "start": "nuxt-ts start",
"generate": "nuxt generate" "generate": "nuxt-ts generate",
"lint": "tslint --project ."
}, },
"devDependencies": { "devDependencies": {
"ts-loader": "^5.3.1", "@types/node": "^10.12.18",
"typescript": "^3.1.6" "tslint-config-standard": "^8.0.1"
} }
} }

View File

@ -1,41 +1,15 @@
<template> <template>
<section class="pa4"> <HelloWorld />
<div class="bg-white-90 pa4">
<div class="f1">
Nuxt TypeScript Starter
</div>
<div class="f3">
Selected Person: {{ selectedPerson.first_name }} {{ selectedPerson.last_name }}
</div>
{{ selected }}
</div>
<div class="flex flex-wrap ph2 justify-between bg-white-80">
<div v-for="person in people" :key="person.id">
<Card :person="person" />
</div>
</div>
</section>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue' import { Component, Vue } from 'vue-property-decorator'
import Component from 'nuxt-class-component' import HelloWorld from '~/components/HelloWorld.vue'
import Card from '~/components/Card.vue'
import { namespace } from 'vuex-class'
import * as people from '~/store/modules/people'
const People = namespace(people.name)
@Component({ @Component({
components: { components: {
Card HelloWorld
} }
}) })
export default class extends Vue { export default class Home extends Vue {}
@People.State selected
@People.State people
@People.Getter selectedPerson
}
</script> </script>

View File

@ -1,5 +0,0 @@
import axios from 'axios'
export default axios.create({
baseURL: process.env.baseUrl
})

View File

@ -0,0 +1,3 @@
export default () => {
console.log(`Hello from ${process.server ? 'Server' : 'Client'} !`)
}

View File

@ -1,23 +1,27 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"lib": [ "module": "esnext",
"dom",
"es2015"
],
"module": "es2015",
"moduleResolution": "node", "moduleResolution": "node",
"lib": ["es2015", "dom"],
"esModuleInterop": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"noImplicitAny": false,
"noImplicitThis": false,
"strictNullChecks": true,
"removeComments": true,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"allowJs": true, "allowJs": true,
"sourceMap": true,
"strict": true,
"allowSyntheticDefaultImports": true,
"noImplicitAny": false,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": true,
"baseUrl": ".",
"paths": { "paths": {
"~/*": ["./*"] "~/*": ["./*"]
} },
"types": [
"@types/node",
"@nuxt/vue-app-edge"
]
} }
} }

View File

@ -0,0 +1,9 @@
{
"defaultSeverity": "error",
"extends": [
"tslint-config-standard"
],
"rules": {
"prefer-const": true
}
}

View File

@ -2,6 +2,9 @@ import Vue from "vue";
import VueRouter, { Route } from "vue-router"; import VueRouter, { Route } from "vue-router";
import { Store } from "vuex"; import { Store } from "vuex";
// augment typings of NodeJS.Process
import "./process";
// augment typings of Vue.js // augment typings of Vue.js
import "./vue"; import "./vue";

12
packages/vue-app/types/process.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
/**
* Extends NodeJS.Process interface
*/
declare namespace NodeJS {
interface Process {
browser: boolean;
client: boolean;
server: boolean;
static: boolean;
}
}