Tag: TypeScript

Debugging VueJS + TypeScript with VS Code

I recently asked a developer working with VueJS how they do debugging and they told me console.log. Not wanting to go back to the dark ages of development I went and found the solution myself.

The VueJS website has a guide on how to do debugging with VS Code https://vuejs.org/v2/cookbook/debugging-in-vscode.html however the instructions they give don't work with TypeScript. Interestingly it does get you far enough to set breakpoints within either Chrome or Edge, but I don't really count that as a solution. The idea of debugging is you step through your code and see everything that is happening, not step through a copy of your code and then go and find the corresponding file in your code editor.

After a bit of digging I managed to get it to work, so here's my solution.

Prerequisites

This part is essentially as per the VueJS guide.

Make sure you have VS Code installed and install the Debugger for Chrome. Don't worry if you use Edge, the same extension will work.

Create your project with the vue-cli, following the instructions in the Vue CLI Guide. When you do this make sure you pick Typescript.

Displaying Source Code in the Browser

This isn't what we're after but it's still a step we must do.

Create a file called vue.config.js in the root of your solution and paste the following into it. This creates the mapping for the debugger to map compressed files back to the original.

module.exports = {
configureWebpack: {
  devtool: 'source-map'
}
}

Configure debugging from VS Code

In VS Code select the Run and Debug button on the left and click the Run and Debug button. If you don't see this button it probably means that you already have a launch.json file defined. Instead a cog will appear at the top to edit the existing settings.

VS Code Run and Debug

From the options choose either Chrome or Edge.

VS Code select Chrome

This will create a launch.json file with some defaults filled out. Replace the contents of the file with the below (this is the part which differs from the instructions on VueJS's site).

I have included 2 configurations, one for debugging with Chrome and the other for Edge. They are both essentially the same and just launch a different browser.

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
  {
    "type": "pwa-msedge",
    "request": "launch",
    "name": "vuejs: edge",
    "url": "http://localhost:8080",
    "webRoot": "${workspaceFolder}",
    "breakOnLoad": true,
    "sourceMapPathOverrides": {
        "webpack:///./*": "${webRoot}/*"
    },
    "skipFiles": [
        "${workspaceFolder}/node_modules/**/*"
    ]
  },
  {
    "type": "chrome",
    "request": "launch",
    "name": "vuejs: chrome",
    "url": "http://localhost:8080",
    "webRoot": "${workspaceFolder}",
    "breakOnLoad": true,
    "sourceMapPathOverrides": {
        "webpack:///./*": "${webRoot}/*"
    },
    "skipFiles": [
        "${workspaceFolder}/node_modules/**/*"
    ]
  }
]
}

Debug from VS Code

To start your debugging you still need to start the application from a terminal with npm run serve. The debugging experience is more like Visual Studios attaching to a process rather than running application by clicking start.

Once your application is running, to attach the debugger either press either F5 or go to the run and debug tab, make sure your browser of choice is selected and click the green play button. Your browser of choice will now open and VS Code should be attached and any break points you create will be hit.

Typescript: What to do when your third party NPM module doesn't have type declarations

As a developer who has probably spent slightly more time doing backend work than front end, and also who's front end work has been more about SPAs than making things look pretty, I really like what TypeScript brings to writing JavaScript. While it's often a nice break from C# to do write some code that doesn't require you to go and define every object there obviously a lot of benefits to do this (otherwise we would just make everything dynamic in C'#). Having file name's show up red in VS Code when there's a type error is a really nice feature.

However if you want to set your compiler options to strict, you will more than likely run into an issue with third part code coming from NPM. In the form of:

Type error: Could not find a declaration file for module MODULE NAME HERE

Here's a screen grab of the compiler error from my build server...

It's offering a nice line of hope by suggesting I run an npm command to add in the types. Sometime this works, but as not everyone feels the need to adopt TypeScript you'll find there's times when it doesn't.

The only solution to this is to write your own.

Type Definitions are stored in the node_modules folder, but as that isn't something you'll want to be adding to source control you'll need another folder. I call mine @types and have it in the root. Within that folder you then need a folder for each module requiring type definitions. The name of each folder should match the module name.

Here's mine:

To make the actual declaration file you'll need to name it index.d.ts and place it in the folder you just created. You can read more about how declaration files should be structured here, however there's an issue with writing a declaration file for a third party module.

1. It's very confusing to work out everything that should go in it

2. It's not your module so it might change

Unless your planning on helping develop the module and create the official type declarations, I suggest an easier option.

Create a file that looks like this:

/// <reference types="node" />

declare module 'module name here';

This is enough to satisfy the compiler. You won't get accurate types for the module, but they would only ever be as good as your interpretation anyway. This will at least unlock the ability for the rest of your application to continue functioning for strict type checking.

Sitecore SPEAK 3 - Creating an application

At the end of last year I wrote a post on A first look at Sitecore SPEAK 3 which gave an overview of what Speak is, and the large architecture change that has happened between Speak 1/2 to 3.

In this post I'm going to share my experience on how to set up a Speak 3 application with Angular.

Step 1 - Creating the Angular project

To start your going to need a few things installed:

  • An IDE - I'm using VS Code
  • NodeJs - This is to get access to node package manager and to run your application in debug mode
  • Angular

If you don't already have Node and Angular installed, I suggest going through Angular's quick start guide. If your also new to Angular I suggest going through their Tour of Heroes tutorial first. This will give you a good understanding of how Angular applications are built and some knowledge around a few key files.

One you've got everything installed, create a new angular project from the command line.

ng new app-name

At this point you could try manually installing the various modules Sitecore provide, covering things like common components, logout functionality etc. However I personally found this a bit awkward. Unless you know what your doing your probably going to run into issues such as compatibility between the latest version of Angular and the Sitecore components (at time of writing Angular is on version 5 but Speak 3 only supports Angular 4).

Instead I would recommend downloading the sample application from https://dev.sitecore.net/Downloads/Sitecore_SPEAK/3/Sitecore_SPEAK_3.aspx and then copy over the .npmrc and package.json file to your solution.

By including these files, the .npmrc file will add a reference to Sitecores package repository and the package.json file will make sure the right packages and versions will be installed. Use npm to install the packages.

npm install

Next we need to update a couple of files in the application to reference some Sitecore specific bits. This is explained in Sitecores documentation, in my examples though I've also included referencing some modules that you are likely to use.

app.module.ts

The app module file defines the modules that are going to be used in the application. Here we need to add the references to the Sitecore modules.

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { ScAccountInformationModule } from '@speak/ng-bcl/account-information'; import { ScActionBarModule } from '@speak/ng-bcl/action-bar'; import { ScApplicationHeaderModule } from '@speak/ng-bcl/application-header'; import { ScButtonModule } from '@speak/ng-bcl/button'; import { ScGlobalHeaderModule } from '@speak/ng-bcl/global-header'; import { ScGlobalLogoModule } from '@speak/ng-bcl/global-logo'; import { ScIconModule } from '@speak/ng-bcl/icon'; import { ScMenuCategory, ScMenuItem, ScMenuItemLink, ScMenuModule } from '@speak/ng-bcl/menu'; import { ScTableModule } from '@speak/ng-bcl/table'; import { ScPageModule } from '@speak/ng-bcl/page'; import { CONTEXT, DICTIONARY } from '@speak/ng-bcl'; import { NgScModule } from '@speak/ng-sc'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, ScAccountInformationModule, ScActionBarModule, ScApplicationHeaderModule, ScButtonModule, ScGlobalHeaderModule, ScGlobalLogoModule, ScIconModule, ScPageModule, ScMenuModule, ScTableModule, NgScModule.forRoot({ contextToken: CONTEXT, // Provide Sitecore context for SPEAK 3 Components (optional) dictionaryToken: DICTIONARY, // Provide translations for SPEAK 3 Components (optional) translateItemId: '0C979B7C-077E-4E99-9B15-B49592405891', // ItemId where your application stores translation items (optional) authItemId: '1BC79B7C-012E-4E9C-9B15-B4959B123653' // ItemId where your application stores user access authorization (optional) }) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

app.component.ts

The component file needs updating to call init on the ngScService.

import { Component, OnInit } from '@angular/core'; import { NgScService } from '@speak/ng-sc'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { constructor( private ngScService: NgScService ) {} ngOnInit() { this.ngScService.init(); } }

.angular-cli.json

In the angular-cli.json file you will see a styles section which references the main css file in the solution. Here you will need to add an additional reference to Sitecores css file.

../node_modules/@speak/styling/dist/styles/sitecore.css

Launch

You can now launch your application from the command line and see the default start screen.

ng serve --open

Step 2 - Building your application

It's not time to start building your application. If you don't know Angular I suggest going through a couple of tutorials, and go from there. I'm not going to go into any details about how Angular apps are and should be written, but I am going to go through a few of the Sitecore controls needed to make an application that fit's the Sitecore admin.

Example Page

To make this page first I cleared out everything from app.component.html and started adding some Sitecore components. Normally you would start generating your own components to represent things like pages, but for the purposes of the example I placing everything in the one file.

To start I have a sc-page containing a header. This comes out of Sitecores demo application and will give you the standard bar that sites at the top of the Sitecore admin, informing users where they are.

<div> <a href="#"></a> <!-- AccountInformation gets accountName and accountImageUrl automatically from Sitecore context which is configured in AppModule --> </div>

To create the menu I'm using an sc-menu. Notice how some items are marked as active.

<aside> <a>Menu item 1</a> <a>Menu item 2</a> <a>Menu item 3</a> <a>Menu item 4</a> </aside>

Lastly to create the main content of the page I'm using a scPageAppHeader, scPageContent and an scTable for the table.

<div> </div> <article> <table> <thead> <tr> <th>Name</th> <th>Status</th> <th>Created by</th> <th>Created data</th> </tr> </thead> <tbody> <tr> <td>Lorem</td> <td>Active</td> <td>sitecore\admin</td> <td>Jan 20, 2018</td> </tr> <tr> <td>Ipsum</td> <td>Active</td> <td>sitecore\admin</td> <td>Jan 20, 2018</td> </tr> <tr> <td>Foop</td> <td>Inactive</td> <td>sitecore\admin</td> <td>Jan 22, 2018</td> </tr> </tbody> </table> </article>

The complete code looks like this:

<div> <a href="#"></a> <!-- AccountInformation gets accountName and accountImageUrl automatically from Sitecore context which is configured in AppModule --> </div> <aside> <a>Menu item 1</a> <a>Menu item 2</a> <a>Menu item 3</a> <a>Menu item 4</a> </aside> <div> </div> <article> <table> <thead> <tr> <th>Name</th> <th>Status</th> <th>Created by</th> <th>Created data</th> </tr> </thead> <tbody> <tr> <td>Lorem</td> <td>Active</td> <td>sitecore\admin</td> <td>Jan 20, 2018</td> </tr> <tr> <td>Ipsum</td> <td>Active</td> <td>sitecore\admin</td> <td>Jan 20, 2018</td> </tr> <tr> <td>Foop</td> <td>Inactive</td> <td>sitecore\admin</td> <td>Jan 22, 2018</td> </tr> </tbody> </table> </article>

To avoid some build errors later on we also need to update the app.components.ts file (think of this as a code behind file), to have an additional property and service.

import { Component, OnInit } from '@angular/core'; import { NgScService } from '@speak/ng-sc'; import { SciLogoutService } from '@speak/ng-sc/logout'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { isNavigationShown = false; constructor( private ngScService: NgScService, public logoutService: SciLogoutService ) {} ngOnInit() { this.ngScService.init(); } }

How to find more components

Unfortunately the Sitecore documentation doesn't currently contain a list of what's available. However if you look in your node_modules folder there is a change log containing information on each component here \node_modules\@speak\ng-bcl\CHANGELOG.md.

Step 3 - Publishing the application

Once you've built the application you need to publish it and copy it into Sitecore.

There are some differences in the way a Speak 3 Angular application needs to work which differ from the normal way an Angular application runs. Among others these include having an index.apsx page rather than an index.html and the application not being located in the root of a site. You can read more about this in Sitecores documentation. The good news though is Sitecore have provided a post build step to sort this out for you.

If you copied the package.json file at the beginning this will already be set up, one thing you do need to do though is update the base location to be where your application is going to live.

Once this is done you can run a build.

npm run-script build

Note this is using npm to run the build script from the packages.json file rather than doing a regular ng build from Angulars CLI.

If all succeeds your dist folder will now contain a compiled version of the application.

Copy these files into the destination folder in your Sitecore site. For me this is \sitecore\shell\client\Applications\Speak-Example. You should now be able to log in and view your application.

Notice the logout button now functions and the current user is displayed in the top right. The menu sections are also collapsible, but other than that our application doesn't actually do anything.

Moving on from this there's lot's more to cover on building out the functionality in the application and you may have also noticed in the app.module.ts file a reference for translations which I never created, but this should be enough to get anyone started with building an Angular Speak 3 project and then publishing it into Sitecore.

Related Links

Speak 3 Official documentation
Speak 3 Downloads