Convert existing Nuxt app to Typescript part 1
Nuxt-ts was announced recently and I was really excited as I was working on a nuxt app with a ASP.NET Core backend. As I have already spent a bit of time working on this, I felt it would be easier/more educational to convert the project manually rather than re-scaffold and copy contents over.
This will be an ongoing project chronicling my adventure into Nuxt with Typescript. First we will create a nuxt app and then convert it to a typescript app. This will reference the hackernews-nuxt-typescript repository as well as the Vue-cli typescript scaffolding to find a happy medium that works best with VSCode.
Before getting started, install the below dependencies:
- Yarn
In this part:
- Scaffold a new Nuxt app
- Change dependencies to typescript versions
- Update package.json scripts to the new dependencies
- Port configuration to typescript
- Port Single File Components to Typescript
Scaffold a new Nuxt app
run npx create-nuxt-app my-typescript app
section | values |
---|---|
serverside framework | None |
features | linter/formatteraxiosprettier |
UI framework | Buefy |
test | Jest |
package manager | yarn |
lets install the dependencies and run this to make sure: yarn && yarn dev
Change dependencies to typescript versions
first add vue-property-decorator
to the app via yarn: yarn add vue-property-decorator
open package.json
and change the entry from "nuxt": "^2.X.X"
to "nuxt-ts": "latest"
next, add the prettier linter to the devDependencies
below:
"tslint-config-prettier": "1.18.0"
NOTE: This will work, but some items will not lint before compile errors.
Update package.json scripts to the new dependencies
replace:
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
with:
"dev": "nuxt-ts",
"build": "nuxt-ts build",
"start": "nuxt-ts start",
"generate": "nuxt-ts generate",
lets run this and see the progress yarn dev
There should be a prompt to create a tsconfig.json
as it is missing; press yes.
The serverside framework was set to None
when the Nuxt app was created… but there is a server being built.
looking at the page we will find missing css and errors saying:
[Vue warn]: Unknown custom element: <b-icon> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
The server being built is a hint; nuxt.config.js
is not being loaded and a default is executed in place. Because the default doesn’t use Buefy, the b-icon
is also not resolved and a warning is thrown. This is fixed in the next step.
Port configuration to typescript
Change the name of nuxt.config.js
to nuxt.config.ts
Then change the module.exports =
to export default
The default page should be showing with Buefy again.
Port Single File Components to Typescript
NOTE: This section has a variety of pitfalls, so lets go through the common ones as the show up.
First convert layouts/default.vue
to the vue-property-decorator
:
- change the script language to ts and add the component decorators
...
<script>
export default {
...
...
<script lang="ts">
import {Vue, Component} from 'vue-property-decorator'
@Component
export default App extends Vue {
...
There should be an error similar to the one below:
This is caused by property decorators being an experimental typescript feature. Enable them by adding the below to tsconfig.json
compilerOptions
:
"compilerOptions": {
"baseUrl": ".",
"types": [
"@types/node",
"@nuxt/vue-app"
],
"experimentalDecorators": true, // add this
}
NOTE: this may require a restart for VSCode to understand the tsconfig changes
Next, do the same for pages/index.vue
in the script
section change:
<script>
import Card from '~/components/Card'
export default {
name: 'HomePage',
components: {
Card
}
}
to:
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import Card from '~/components/Card'
@Component({
components: {
Card
}
})
export default class HomePage extends Vue {}
There should be another error here:
This one is trickier and has some history(spoilers it’s really long). Typescript, by default, will only look for files with extension .ts
and there seems to be two methods of fixing this. One is to modify the webpack config and the other is to extend the typing definitions with a shim as it is easier than extending webpack (personal opinion only, don’t @me).
Add a shims.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
NOTE: A VSCode restart may be required to pickup the changes
Next change components/Card.vue
from:
<script>
export default {
props: {
title: {
type: String,
required: true
},
icon: {
type: String,
required: true
}
}
}
to:
<script lang="ts">
import {Vue, Component, Prop} from 'vue-property-decorator';
@Component
export default class Card extends Vue {
@Prop({
required: true
})
title!: string;
@Prop({
required: true
})
icon!: string;
}
Some brief tips:
- The
@Prop
decorator takes on all the definitions property definitions that typescript is not built for (namely if the property is required and the default value). - The
!
after the property name is to declare that the property can be unintialized (the@Prop
makes it reactive) because it is set during the vue lifecycle.
Extras: tweaking the linter/formatter
For the most part, the prettier formatter works well. Coming from a C# background however, I would like a couple of changes. namely semicolons at the end of statements.
Official docs says that adding "semi": true"
to .prettierrc
should work.
Next, increase the max line length by setting "printWidth": 120
in the .prettierrc
file.
Lastly, add commas to everything! "trailingComma": "all"
This will conclude part 1. Any corrections can be sent via Twitter DM