Fun with Promises in JavaScript and TypeScript

If you’re writing asynchronous code – especially Javascript or Typescript – I have a story to share. It all started when I needed to initialize the Microsoft Teams JavaScript SDK for use in a web application I’m writing. It’s just a simple call in the browser:

await microsoftTeams.app.initialize();

This is all pretty easy, but the docs say you should only call initialize()  once and my app is a bit complex, with multiple web components that are rendered in parallel, and two of them need to use the Teams SDK on page load. So how can I prevent initialize() from being called more than once while isolating code within my web components?

Singleton promises

To prevent the multiple calls, I reached into my bag of geeky developer tricks and made this little function so it would only be called once:

Continue reading

Setting up SSL for tabs in the Teams Toolkit for Visual Studio Code

I’ve started using the new Microsoft Teams toolkit, which is a Visual Studio Code extension and generator for Teams applications. One thing I noticed is a little challenge when creating tabs, and that’s due to the requirement to use SSL. The documentation is fine and explains how to trust your local project, but I found it a little painful since the certificates only last 1 month and there’s a different one for each project, so I need repeat the process frequently. Your teammates will need to do that as well.

Default certificate from localhost

Here is an alternative approach in which you create your own certificate authority and build certs from that so you can install just one root certificate across all your projects! Each teammate can have their own certs, so you can collaborate as much as you wish and nobody has to go installing certs.

NOTE: Did you know that the Teams Toolkit uses Create React App (CRA) for tabs? Create React App is a toolchain from Facebook (who created React in the first place) it’s very popular and well supported! If you need help, search on “Create React App” and you can find a plethora of helpful articles; this one helped me figure this out!

Step 1: Create and trust a certificate authority (CA)

This step only needs to be done once for as many projects as you wish. It assumes you already have Node.js installed, as required by the Teams Toolkit.

a. Create a safe/private folder somewhere and go there in your favorite command-line tool, and run these commands:

npm install -g mkcert
mkcert create-ca --organization "MyOrg" --validity 3650
mkcert create-cert --ca-key "ca.key" --ca-cert "ca.crt" --validity 3650

NOTE: 3650 is the number of days your certs will be valid; feel free to change it. You can use --help on mkcert to reveal other options, such as setting an organization name and location (the default org is “Test CA”) and customizing the domain names for your certificate (the default is “localhost,127.0.0.1”).

This will create a new Certificate Authority and a certificate that was issued from it. You should see 4 files:

FileDescription
ca.crtCertificate for your new CA
ca.keyPrivate key for your new CA
cert.crtCertificate for use in projects
cert.keyPrivate key for use in projects

b. Now you need to trust the certificate for your new CA; by doing that any cert you create will be trusted with no additional action on your part.

On Windows

  • Double click on the ca.crt file and click “Install Certificate”.
  • Choose Local Machine and click next.
  • Select “Place all certificates in the following store” and then click the “Browse” button. Choose “Trusted Root Certification Authorities” click “OK” to close the dialog box, and then click “Next”.
  • Restart all instances of your browser to force it to re-read its trusted roots. If in doubt, reboot your computer.

On Mac

  • Double click on the ca.crt file, which should be found under /Users/[your-name]/. It will launch Keychain Access app.
  • Enter your password or use Touch ID when prompted. 
  • The new certificate (in this case, “MyOrg”) should be added. Double-click it. 
  • In a new window, expand the Trust section of the certificate details. Select “Always Trust” for every option. 
  • Close the window. Enter your password or use Touch ID again if you are asked. Now the certificate is trusted. 
  • Restart all instances of your browser to force it to re-read its trusted roots. If in doubt, reboot your computer.

On Linux

There are more steps on Linux as most browsers don’t use the operating system’s certificate store, and a tool called certutil is needed to modify the browsers’ cert?.db files. This article explains how to install your new root certificate on Linux.

Step 2 – Add the certs to your project

This is what you need to do for each project.

a. Create a new folder in your project folder (the same level as the package.json file) called .cert. Copy the cert.crt and cert.key files into this folder.

b. Modify your .env file to tell the local web server to use your cert:

HTTPS=true
SSL_CRT_FILE=./.cert/cert.crt
SSL_KEY_FILE=./.cert/cert.key

c. Prevent saving the certs to your git repository by adding a line to the .gitignore file.

.cert

Azure Active Directory SSO Tabs

Tabs that implement Azure Active Directory Single Sign-On need to implement more than just a web page; they need to implement a web service to exchange the SSO token for an access token that the app can use to call downstream services such as the Microsoft Graph. This is explained in this blog article, or this one, more clearly than in the documentation.

When yo teams generates an SSO tab, this web service is hosted using the same web server as the page itself.

When the Teams Toolkit generates one, however, it creates a separate web service for the web service so there really are two endpoints that need to be SSL enabled. The web service is in a folder called api-server. To enable SSL here, follow these steps:

  1. Add these lines to the api-server\.env file.

HTTPS=true
SSL_CRT_FILE=../.cert/cert.crt
SSL_KEY_FILE=../.cert/cert.key
CORS_ORIGIN=https://devappsforteams.local:3000

2. Immediately above the line app.get('/getGraphAccessToken') in server.ts or server.js, add these lines to allow the cross-origin call from the web page (port 3000) to the web service (port 5000):

const cors = require('cors');
app.use(cors({
    origin: process.env.CORS_ORIGIN
}));

3. Near the bottom of the same file, replace the line

app.listen(port);

with this code:

const fs = require('fs');
const https = require('https');
var privateKey = fs.readFileSync(process.env.SSL_KEY_FILE );
var certificate = fs.readFileSync(process.env.SSL_CRT_FILE);

https.createServer({
    key: privateKey,
    cert: certificate
}, app).listen(port);

Working in a team

Each team member needs to do Step 1 on their computer just once. When a developer starts working on a project they can simply copy their .cert folder into their project and go to work.

Many thanks to my colleague Tomomi Imura for documenting the Mac instructions and providing screen shots.

Do you have ideas on how to do this better, especially in a project team? Please chime in using the comments; thanks!

Branding SharePoint: The New Normal

Modern SharePoint is catching on, and sites are looking better than ever right out of the box. With mobile-ready pages and easier editing, customers and partners are starting to ask for it. And as SharePoint 2019 brings the modern experience on premises, the demand is likely to grow even more.

Yet even as sites look better than ever “out of the box”, there are constraints on how they can be customized. Partners and customers who want to completely change the look sometimes run into these boundaries and get frustrated.

Continue reading

What is Modern SharePoint and Why Should I care?

The question I get the most these days is, “what is this modern SharePoint you keep talking about?” It might sound like an oxymoron! All my SharePointy friends know about it, and debate the finer points over beer at SharePint, but to the casual user, or someone who’s been working on premises, it may be a bit of a mystery. It’s only available online (at the time of this writing anyway), and is slowly being phased in as developers build it out.

So here it is: Microsoft is on a mission to modernize SharePoint, to save it from fading into obscurity as a once innovative but now persnickety old war horse of a product. This article will explain how they’re doing it, and why you might want to take a fresh look on this stalwart collaboration product.

Continue reading

Building Compliant Team Sites

Companion article to my session at Microsoft Ignite 2017

Thanks to everyone who attended my session at Microsoft Ignite 2017, Building Compliant Team sites (THR2057). For those who missed it, here is the recording. This article provides links to resources and additional details.

The talk was about how enterprises can manage modern SharePoint team sites in a way that makes compliance easy.

Continue reading

ALM for Widget Solutions

Colleague and fellow SharePoint developer Brian McCullough asked a great question on Twitter:

tweetfrombrianc

This is such an important topic I thought it was worth more than a 140-character reply; hence this article. Whole books have been written on Application Lifecycle Management,and there are many facets beyond simple software deployment, but this article will focus on the baseline needs of a typical “widget” project:

  • Allow reliable and repeatable movement from a development environment to test and ultimately into production potentially across dozens or thousands of SharePoint sites
  • Support this not just once, but repeatedly as project versions are developed and released. If the project includes persistent data, this should be preserved (and perhaps enhanced) as part of the upgrade process

In a widget project, each “environment” may just be a couple of site collections; for example you could have site collections for dev, staging, and production all in the same tenant on farm. Since widgets run on the client side, there’s no need for them to interfere. If you’re on Office 365, you might want a First Release tenant to test your code with forthcoming updates to the platform while keeping your main staging and production environments on the standard release schedule.

Continue reading

New Performance Best Practices for SharePoint Online Portals

or, Avoiding the BLOB (and other) caches in SharePoint Online

SharePoint was designed to work best in relatively small farms on premises. A typical configuration has 2-4 web front-ends, so caching information on the web servers is a good strategy. In SharePoint Online, however, a typical farm has hundreds of web front-ends, and is shared by many tenants. As a result, the chance of finding cached content for any given tenant on any given server is greatly reduced, and server side caching is ineffective. That changes some key best practices for building SharePoint portals; in Office 365, it’s best to avoid SharePoint features that rely heavily on server-side caching.

An excellent session at Microsoft Ignite, Learn how to build a fast, responsive SharePoint portal in SharePoint Online, focused on this and other performance considerations in SharePoint Online. This article will call out key best practices to optimize portal solutions hosted in Office 365.

Continue reading

Flexible SharePoint Development with Widget Wrangler

(Cross posted at Julie Turner’s blog, SharePoint Customization: Vedi, Vini, Vici)

What’s a widget, and why should I care?

In economics, a widget is a name for a generic gadget or manufactured good; on the web, a widget is a generic piece of web functionality running on a page. What makes widgets special is that, unlike controls in ASP.NET or directives in AngularJS, widgets are generally released separately from the web page that hosts them, and are often deployed by end users.

If you’re reading this blog, you probably know something about Microsoft SharePoint, and this might sound familiar. A widget is a lot like a web part, only much lighter weight. In fact, widgets can easily be hosted in content editor web parts, on a list form, in a SharePoint add-in, or outside of SharePoint. If you’re careful, you can reuse the same widget in all those contexts!

Continue Reading