Welcome back everyone. Hope you had time to read and absorb the first article in the series Hosting a Vue 3 application in .NET 6. We went over a lot with setting up our basic host in .NET but didn't really do much on the client application side. Today were not going to do any real development but were going to go ahead and configure typescript support since Vue 3 is written in typescript. The source code for this article series can be found on Github.
Packages
The first thing were going to need to do is add a few packages to our devDependencies
in package.json
. To enable support were going to need to add both ts-loader
and typescript
. Go ahead and add the latest of each so we can be using the latest and greatest, intellisense should show you the versions. Our setup is also going to require the installation of 2 types packages to the devDependencies
so go ahead an add both @types/webpack-env
and @types/jest
Now that you have updated your package.json
go ahead and on a terminal or command line run npm install
to make sure your ready for development.
Adding a shim for Vue files
Since Typescript knows nothing about Vue, or heck even anything other than javascript or typescript, we need to add a shim so we can tell the compiler and webpack what to do with vue files when it sees an import statement with a .vue
file. In the root of the ClientApp folder go ahead and add a new folder, name it @types. In this folder add a new file vue.d.ts. Your solution should look something like the following.
Great, so now we need to add the actual shim. There are a few ways to do this but the strongest typed is that from the shim that you get from creating a vue cli project so were going to go ahead and use the same. Add the following code to the file
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
So what is this doing? Well its telling the typescript compiler to treat vue files as module and defining what a component is through the use of the DefineComponent function. Why do we need this? Well without it if you try to import a .vue file your going to get compile errors, the same is needed should you want to import something like a css file or mdx in react. Now I've been doing typescript for a while but not with Vue so this was new to me, after some Googling around the best explanation I could found was on a stack over flow post that linked to this blog about typescript modules. After reading this it will make more sense hopefully.
Typescript config
Now that we have Vue file support shimmed into our application we need to configure the typescript compiler. To do this go ahead an add a tsconfig.json
to the root of the project. Add the following json to the file
{
"compilerOptions": {
"allowJs": true,
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@t/*": [ "./ClientApp/@types/*" ],
"@c/*": [ "./ClientApp/components/*" ],
"@/*": [ "./ClientApp/*" ]
},
"types": [
"webpack-env",
"jest"
],
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"exclude": [
"./node_modules"
],
"include": [
"./ClientApp/@types/**/*.d.ts",
"./ClientApp/**/*.ts",
"./ClientApp/**/*.vue"
]
}
So what is this config doing? It may look like a lot but don't worry its not that scary. The config is broken into 3 main sections, the compilerOptions
, the exclude
and include
sections. The last two as their name implies are paths to include and exclude so are fairly simple. We want to exclude node modules and we want all of our code to be included. Currently that would be ./ClientApp/@types typescript files and all typescript and vue files in any folder under ClientApp, well won't the second two catch the types? Yes but I like to be specific and not everyone puts the types in the client app folder, so its just a preference.
Compiler Options
So there are enough settings here that this warrants some discussion as there are quite a lot more settings that were not even using.
- allowJs - as the name implies this allows us to also use plain javascript
- target - what should the compiler output
- module - same as target what kind of modules should be used
- strict - tell the compiler to complain about pretty much everything
- jsx - preserve any jsx
- moduleResolution - use node modules when resolving
- allowSyntheicDefaultImports - allow importing when there is no default export only other exports
- forceConsistentCasingInFileNames - force you to use a consistent file naming pattern
- useDefineForClassFields - Easier if you just read the documentation, but trust me you want it on
- sourceMap - yes we want source maps so we can debug things
- baseUrl - the base url for where we should start looking for ts files in the project
- paths - include paths for the compiler, an alias for the folder resolve
- types - typescript types to load and use, these are the npm packages we installed earlier
- lib - typescript libraries we should load so the compiler knows about things
For a deeper explanation of these settings and others you can read through the docs.
Webpack
Previously we created a main.js and told webpack through our webpack.config.js
to use this as the entry point to our application. To change over to typescript were going to need to first rename the file to main.ts , since the file is simple it can just be renamed and doesn't require any code changes. Second we need to update our webpack config. To do so we need to change the entry line from
entry: {
main: './main.js',
},
to
entry: {
main: './main.ts',
},
Great we have now updated our configuration and pointed webpack and the typescript compiler on where to start working from but were not done yet, we still need to add a loader. To do this we need to add a new rule to webpack.config.js
. The rule should look like the following
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader',
options: {
configFile: path.resolve(__dirname, './tsconfig.json'),
appendTsSuffixTo: [/\.vue$/]
}
}
]
},
What does this rule do? Well its telling webpack when it encounters a ts file that it needs to use the typescript loader we installed, it should resolve our config file and append ts to vue files for processing. Pretty simple right? Thats all we needed to turn on typescript support! You should now be able to run npm run dev/build on the command line and it should build just like before!
Wrapping Up
This was a quick article for our series but pretty important in my opinion. With Vue 2 it was hard to get typescript fully working right but with Vue 3 it was simple and quick which was one of the goals of the developers. Anyways I really hope you enjoyed and are getting thirsty to write some Vue 3 components in the Composition Api using Typescript so stay tuned for our next article where we will create a nav bar and components!
Disclaimer
All screenshots taken in Visual Studio community edition. Visual Studio is copyright Microsoft