diff --git a/NuGet.config b/NuGet.config
index 1b75d58a6a0efa5204166af269e8b8a5579e1133..f56f587302abba245fbda1c72ae97d2c5294c0e0 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -9,5 +9,6 @@
     -->
     <add key="dotnet-core" value="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json" />
     <add key="myget.org aspnetcore-tools" value="https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json" />
+    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
   </packageSources>
 </configuration>
diff --git a/build.ps1 b/build.ps1
index 6e5a86f93c691bb2f0696b2e980fe6e0e2d8d9c0..86fe4a6c5fe87ef1f1e20c09b9919d016721ac37 100644
--- a/build.ps1
+++ b/build.ps1
@@ -306,6 +306,7 @@ $MSBuildArguments += "/p:TargetOsName=win"
 Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1')
 
 try {
+    $env:KOREBUILD_KEEPGLOBALJSON = 1
     Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $PSScriptRoot -ConfigFile $ConfigFile -CI:$CI
     if ($ForceCoreMsbuild) {
         $global:KoreBuildSettings.MSBuildType = 'core'
@@ -315,4 +316,5 @@ try {
 finally {
     Remove-Module 'KoreBuild' -ErrorAction Ignore
     Remove-Item env:DOTNET_HOME
+    Remove-Item env:KOREBUILD_KEEPGLOBALJSON
 }
diff --git a/build/tasks/RepoTasks.csproj b/build/tasks/RepoTasks.csproj
index a6836228db3b835ae920200e5103ce89c5659263..8615952bb7157e8cbcb5747f95e2b9a39c3cebfc 100644
--- a/build/tasks/RepoTasks.csproj
+++ b/build/tasks/RepoTasks.csproj
@@ -14,6 +14,7 @@
     <PackageReference Remove="Internal.AspNetCore.Sdk" />
     <PackageReference Include="NuGet.Build.Tasks" Version="4.9.3" />
     <PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
+    <PackageReference Include="Yarn.MSBuild" Version="1.13.0" />
   </ItemGroup>
 
   <ItemGroup Condition="'$(BuildInstallers)' == 'true' AND '$(TargetOsName)' == 'win'">
diff --git a/eng/targets/Npm.Common.targets b/eng/targets/Npm.Common.targets
index 79f975532f14fd1c3a65c5c15c5a0b37f78c30e2..4138c0893333f5c2717a175fe924e6786447d008 100644
--- a/eng/targets/Npm.Common.targets
+++ b/eng/targets/Npm.Common.targets
@@ -1,11 +1,15 @@
 <Project DefaultTargets="Build" InitialTargets="_CheckForInvalidConfiguration">
 
+  <!-- Version of this SDK is set in global.json -->
+  <Sdk Name="Yarn.MSBuild" />
+
   <PropertyGroup>
     <NormalizedPackageId>$(PackageId.Replace('@','').Replace('/','-'))</NormalizedPackageId>
     <PackageFileName>$(NormalizedPackageId)-$(PackageVersion).tgz</PackageFileName>
     <PackageJson>$(MSBuildProjectDirectory)\package.json</PackageJson>
     <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(MSBuildProjectDirectory)\obj\</BaseIntermediateOutputPath>
     <IntermediateOutputPath>$([MSBuild]::NormalizeDirectory('$(BaseIntermediateOutputPath)'))$(Configuration)\</IntermediateOutputPath>
+    <InstallArgs Condition="'$(RestoreLockedMode)' == 'true'">--frozen-lockfile</InstallArgs>
   </PropertyGroup>
 
   <Target Name="_CheckForInvalidConfiguration">
@@ -13,9 +17,8 @@
   </Target>
 
   <Target Name="Restore">
-    <Message Importance="High" Text="Running npm install on $(MSBuildProjectFullPath)" />
-    <Exec Command="npm ci" Condition="'$(CI)' == 'true'" />
-    <Exec Command="npm install --no-optional" Condition="'$(CI)' != 'true'" />
+    <Message Importance="High" Text="Running yarn install on $(MSBuildProjectFullPath)" />
+    <Yarn Command="install $(InstallArgs)" />
   </Target>
 
   <Target Name="PrepareForBuild">
@@ -28,7 +31,7 @@
   </Target>
 
   <Target Name="Build" DependsOnTargets="PrepareForBuild;ResolveProjectReferences">
-    <Exec Command="npm run build" IgnoreStandardErrorWarningFormat="true" Condition="'$(IsBuildable)' != 'false'" />
+    <Yarn Command="run build" Condition="'$(IsBuildable)' != 'false'" StandardOutputImportance="High" StandardErrorImportance="High" />
   </Target>
 
   <PropertyGroup>
@@ -50,8 +53,8 @@
 
     <Copy SourceFiles="$(PackageJson)" DestinationFiles="$(_BackupPackageJson)" />
 
-    <Exec Command="npm --no-git-tag-version --allow-same-version version $(PackageVersion)" StandardOutputImportance="Normal" StandardErrorImportance="Normal" />
-    <Exec Command="npm pack" StandardOutputImportance="Normal" StandardErrorImportance="Normal" />
+    <Yarn Command="version --no-git-tag-version --new-version $(PackageVersion)" />
+    <Yarn Command="pack --filename $(PackageFileName)" />
 
     <Move SourceFiles="$(_PackageTargetPath)" DestinationFolder="$(PackageOutputPath)" />
     <Message Importance="High" Text="$(MSBuildProjectName) -> $(_PackageTargetPath)" />
@@ -66,7 +69,7 @@
 
   <Target Name="Test" Condition="'$(IsTestProject)' == 'true'">
     <Message Importance="High" Text="Running npm tests for $(MSBuildProjectName)" />
-    <Exec Command="npm $(NpmTestArgs)" IgnoreStandardErrorWarningFormat="true" />
+    <Yarn Command="$(NpmTestArgs)" StandardOutputImportance="High" StandardErrorImportance="High" />
   </Target>
 
 </Project>
diff --git a/global.json b/global.json
index b4fc896ff3e7785d5071c9a55c24d12aa5b40d9c..8a1e66d6bf237e9d17f1d9597d6ff2da46eca23a 100644
--- a/global.json
+++ b/global.json
@@ -3,6 +3,6 @@
     "version": "3.0.100-preview-010184"
   },
   "msbuild-sdks": {
-    "Internal.AspNetCore.Sdk": "3.0.0-build-20190219.1"
+    "Yarn.MSBuild": "1.13.0"
   }
 }
diff --git a/src/Components/Browser.JS/src/Microsoft.AspNetCore.Components.Browser.JS.npmproj b/src/Components/Browser.JS/src/Microsoft.AspNetCore.Components.Browser.JS.npmproj
index f2215281b4d54ac893ed1df96873dfd54554589b..93d6097acfe14a43c788495e294e7c26c97a0822 100644
--- a/src/Components/Browser.JS/src/Microsoft.AspNetCore.Components.Browser.JS.npmproj
+++ b/src/Components/Browser.JS/src/Microsoft.AspNetCore.Components.Browser.JS.npmproj
@@ -17,8 +17,8 @@
           Inputs="@(WebpackInputs)"
           Outputs="dist\components.webassembly.js;dist\components.server.js">
     <RemoveDir Directories="dist" />
-    <Exec Command="npm run build:debug" Condition="'$(Configuration)' == 'Debug'" />
-    <Exec Command="npm run build:production" Condition="'$(Configuration)' != 'Debug'" />
+    <Yarn Command="run build:debug" Condition="'$(Configuration)' == 'Debug'" />
+    <Yarn Command="run build:production" Condition="'$(Configuration)' != 'Debug'" />
   </Target>
 
 </Project>
diff --git a/src/Components/Browser.JS/src/package.json b/src/Components/Browser.JS/src/package.json
index 0a25d7414c99be94d5b5c0fcc863e7933b59de48..bbbe8e840a48a95aa2d33106ccc303bbaaae690b 100644
--- a/src/Components/Browser.JS/src/package.json
+++ b/src/Components/Browser.JS/src/package.json
@@ -1,5 +1,6 @@
 {
   "name": "microsoft.aspnetcore.components.browser.js",
+  "private": true,
   "version": "0.0.1",
   "description": "",
   "main": "index.js",
diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
index 5a886ef6359ab848927f6a24367d73030b3bbea8..c19c9a59fbe2900a33e2c9e21d71edf73801ca46 100644
--- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
+++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj
@@ -18,9 +18,12 @@
     <Compile Include="$(SharedSourceRoot)Process\**\*.cs" LinkBase="Shared" />
   </ItemGroup>
 
-  <Target Name="EnsureNpmRestored" BeforeTargets="Build" Condition="!Exists('node_modules') AND '$(BlazorAllTests)'=='true'">
-    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
-    <Exec Command="npm ci" />
+  <!-- Version of this SDK is set in global.json -->
+  <Sdk Name="Yarn.MSBuild" />
+
+  <Target Name="EnsureNodeJSRestored" BeforeTargets="Build" Condition="'$(BlazorAllTests)'=='true'">
+    <Message Text="Running yarn install on $(MSBuildProjectFile)" Importance="High" />
+    <Yarn Command="install" />
   </Target>
 
   <ItemGroup>
diff --git a/src/Components/test/E2ETest/package.json b/src/Components/test/E2ETest/package.json
index ec0a2b015690d1cd39f8e33f0744739d8bcabf26..a84e769eb42bfe0f4dc96c8e722060bcb1b21fcc 100644
--- a/src/Components/test/E2ETest/package.json
+++ b/src/Components/test/E2ETest/package.json
@@ -3,6 +3,7 @@
   "version": "0.0.1",
   "description": "Not a real package. This file exists only to declare dependencies.",
   "main": "index.js",
+  "private": true,
   "scripts": {
     "selenium-standalone": "selenium-standalone",
     "prepare": "selenium-standalone install"
diff --git a/src/Middleware/CORS/test/FunctionalTests/CORS.FunctionalTests.npmproj b/src/Middleware/CORS/test/FunctionalTests/CORS.FunctionalTests.npmproj
index 4581b617fcfd922802419b0ce7618e37c62e5146..5f99a4e56124f4c8ade482493283e1ab1934e63c 100644
--- a/src/Middleware/CORS/test/FunctionalTests/CORS.FunctionalTests.npmproj
+++ b/src/Middleware/CORS/test/FunctionalTests/CORS.FunctionalTests.npmproj
@@ -14,7 +14,7 @@
 
   <Target Name="InstallPuppeteer" BeforeTargets="Restore">
     <!-- Explicitly install puppeteer. This will install the bundled Chromium as part of restore instead of as part of execution -->
-    <Exec Command="npm install puppeteer" />
+    <Yarn Command="add puppeteer" />
   </Target>
 
   <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Directory.Build.targets))\Directory.Build.targets" />
diff --git a/src/Middleware/CORS/test/FunctionalTests/package.json b/src/Middleware/CORS/test/FunctionalTests/package.json
index 11fcdca4255586dd00ac899c2e261b778ef03676..5c179dd000bf929b8ccb9f5f94f6b29482598fda 100644
--- a/src/Middleware/CORS/test/FunctionalTests/package.json
+++ b/src/Middleware/CORS/test/FunctionalTests/package.json
@@ -1,4 +1,5 @@
 {
+  "private": true,
   "devDependencies": {
     "jest": "^23.6.0",
     "merge": "^1.2.1",
diff --git a/src/Middleware/NodeServices/src/Microsoft.AspNetCore.NodeServices.csproj b/src/Middleware/NodeServices/src/Microsoft.AspNetCore.NodeServices.csproj
index fc460f6afed94bfda0e11e6ec6bca476b07ace79..27df62162b701fc2a82354afebfc87e3195e626a 100644
--- a/src/Middleware/NodeServices/src/Microsoft.AspNetCore.NodeServices.csproj
+++ b/src/Middleware/NodeServices/src/Microsoft.AspNetCore.NodeServices.csproj
@@ -17,8 +17,15 @@
     <Reference Include="Newtonsoft.Json" />
   </ItemGroup>
 
-  <Target Name="PrepublishScript" BeforeTargets="PrepareForPublish" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
-    <Exec Command="npm install" />
+  <!-- Version of this SDK is set in global.json -->
+  <Sdk Name="Yarn.MSBuild" />
+
+  <Target Name="YarnInstall">
+    <Message Text="Running yarn install on $(MSBuildProjectFile)" Importance="High" />
+    <Yarn Command="install" />
+  </Target>
+
+  <Target Name="PrepublishScript" DependsOnTargets="YarnInstall" BeforeTargets="PrepareForPublish" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
     <Exec Command="node node_modules/webpack/bin/webpack.js" />
   </Target>
 
diff --git a/src/Middleware/NodeServices/src/package.json b/src/Middleware/NodeServices/src/package.json
index f234bc6063f1c61850028c65e281721bf7c17587..4cf72434107623805aafcd1491a9971b3e92a40f 100644
--- a/src/Middleware/NodeServices/src/package.json
+++ b/src/Middleware/NodeServices/src/package.json
@@ -2,6 +2,7 @@
   "name": "nodeservices",
   "version": "1.0.0",
   "description": "This is not really an NPM package and will not be published. This file exists only to reference compilation tools.",
+  "private": true,
   "main": "index.js",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
diff --git a/src/Middleware/SpaServices/src/Microsoft.AspNetCore.SpaServices.csproj b/src/Middleware/SpaServices/src/Microsoft.AspNetCore.SpaServices.csproj
index 94ff1d4f92e55ef1a1a41bf6e7bf94456b6ada42..3a165db8c53778f1a65b693a36dace1719100c48 100644
--- a/src/Middleware/SpaServices/src/Microsoft.AspNetCore.SpaServices.csproj
+++ b/src/Middleware/SpaServices/src/Microsoft.AspNetCore.SpaServices.csproj
@@ -20,8 +20,15 @@
     <Reference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" />
   </ItemGroup>
 
-  <Target Name="PrepublishScript" BeforeTargets="PrepareForPublish" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
-    <Exec Command="npm install" />
+  <!-- Version of this SDK is set in global.json -->
+  <Sdk Name="Yarn.MSBuild" />
+
+  <Target Name="YarnInstall">
+    <Message Text="Running yarn install on $(MSBuildProjectFile)" Importance="High" />
+    <Yarn Command="install" />
+  </Target>
+
+  <Target Name="PrepublishScript" DependsOnTargets="YarnInstall" BeforeTargets="PrepareForPublish" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
     <Exec Command="node node_modules/webpack/bin/webpack.js" />
   </Target>
 
diff --git a/src/Middleware/SpaServices/src/package.json b/src/Middleware/SpaServices/src/package.json
index 7ee819c7814aa5d0504e18f7ce4889028c57702f..9e9cd841acfab2bf98bd0ecf7ce772947defc976 100644
--- a/src/Middleware/SpaServices/src/package.json
+++ b/src/Middleware/SpaServices/src/package.json
@@ -2,6 +2,7 @@
   "name": "spaservices",
   "version": "1.0.0",
   "description": "This is not really an NPM package and will not be published. This file exists only to reference compilation tools.",
+  "private": true,
   "main": "index.js",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
diff --git a/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj b/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj
index 1a94cfe658a84c0888c21c23d4494c3a6e1cfdd5..bff023ed16b3dc659915f9ec73e813e32ba4d756 100644
--- a/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj
+++ b/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj
@@ -8,12 +8,10 @@
     <_TestSauceArgs>--verbose --no-color --configuration $(Configuration) --sauce-user "$(SauceUser)" --sauce-key "$(SauceKey)"</_TestSauceArgs>
     <_TestSauceArgs Condition="'$(BrowserTestHostName)' != ''">$(_TestSauceArgs) --use-hostname "$(BrowserTestHostName)"</_TestSauceArgs>
     <NpmTestArgs Condition="'$(DailyTests)' != 'true'">run test:local -- --no-color --configuration $(Configuration)</NpmTestArgs>
-
-
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="FunctionalTests.csproj" Condition="'$(BuildManaged)' != 'false'" />
+    <ProjectReference Include="FunctionalTests.csproj" Condition="'$(BuildManaged)' == 'true'" />
     <ProjectReference Include="..\signalr\signalr.npmproj" />
     <ProjectReference Include="..\signalr-protocol-msgpack\signalr-protocol-msgpack.npmproj" />
   </ItemGroup>
@@ -21,21 +19,20 @@
   <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Directory.Build.targets))\Directory.Build.targets" />
 
   <Target Name="Test" Condition="'$(IsTestProject)' == 'true'">
-    <Message Importance="High" Text="Running npm tests for $(MSBuildProjectName)" />
-    <Exec Condition="'$(DailyTests)' != 'true'" Command="npm $(NpmTestArgs)" IgnoreStandardErrorWarningFormat="true" />
+    <Message Importance="High" Text="Running tests for $(MSBuildProjectName)" />
+    <Yarn Condition="'$(DailyTests)' != 'true'" Command="$(NpmTestArgs)" />
     <CallTarget Condition="'$(DailyTests)' == 'true'" Targets="RunBrowserTests" />
   </Target>
 
   <Target Name="RunBrowserTests">
     <Message Text="Running JavaScript client Browser tests" Importance="high" />
-    <Exec Command="npm run test:inner -- --no-color --configuration $(Configuration)" WorkingDirectory="$(RepositoryRoot)src/SignalR/clients/ts/FunctionalTests" IgnoreStandardErrorWarningFormat="true" />
+    <Yarn Command="run test:inner -- --no-color --configuration $(Configuration)" WorkingDirectory="$(RepositoryRoot)src/SignalR/clients/ts/FunctionalTests" />
     <Message Text="Running JavaScript tests" Importance="high" />
 
     <!-- Skip the "inner" test run when we're running DailyTests -->
-    <Exec Command="npm run test:inner -- --no-color --configuration $(Configuration)"
+    <Yarn Command="run test:inner -- --no-color --configuration $(Configuration)"
           Condition="'$(DailyTests)' != 'true'"
-          WorkingDirectory="$(RepositoryRoot)src/SignalR/clients/ts/FunctionalTests"
-          IgnoreStandardErrorWarningFormat="true" />
+          WorkingDirectory="$(RepositoryRoot)src/SignalR/clients/ts/FunctionalTests" />
 
     <PropertyGroup>
       <BrowserTestHostName Condition="'$(CI)' == 'true'">sauce.local</BrowserTestHostName>
diff --git a/src/SignalR/clients/ts/FunctionalTests/package.json b/src/SignalR/clients/ts/FunctionalTests/package.json
index 02d0cf30e99f90e7bb3ea6f380bd6be6fa1a23fc..f67658af39b1de1f1e58ecc57d038fc3350dbf0d 100644
--- a/src/SignalR/clients/ts/FunctionalTests/package.json
+++ b/src/SignalR/clients/ts/FunctionalTests/package.json
@@ -5,8 +5,8 @@
   "description": "",
   "main": "index.js",
   "dependencies": {
-    "@aspnet/signalr": "file:../signalr",
-    "@aspnet/signalr-protocol-msgpack": "file:../signalr-protocol-msgpack",
+    "@aspnet/signalr": "link:../signalr",
+    "@aspnet/signalr-protocol-msgpack": "link:../signalr-protocol-msgpack",
     "msgpack5": "^4.0.2"
   },
   "devDependencies": {
diff --git a/src/SignalR/clients/ts/signalr-protocol-msgpack/README.md b/src/SignalR/clients/ts/signalr-protocol-msgpack/README.md
index 6541df90ac5d3c7d42fab2d755a683f967ff3079..c4d74f16b5010f287d479dbdd191097ecdb10125 100644
--- a/src/SignalR/clients/ts/signalr-protocol-msgpack/README.md
+++ b/src/SignalR/clients/ts/signalr-protocol-msgpack/README.md
@@ -5,6 +5,10 @@ MsgPack support for SignalR for ASP.NET Core
 ```bash
 npm install @aspnet/signalr-protocol-msgpack
 ```
+or
+```bash
+yarn add @aspnet/signalr-protocol-msgpack
+```
 
 ## Usage
 
diff --git a/src/SignalR/clients/ts/signalr/README.md b/src/SignalR/clients/ts/signalr/README.md
index f38a93401ed65e45d88299ce82dcf913a3bc8c7c..644e4eb2db979b72e70589bc088372e86f9498b8 100644
--- a/src/SignalR/clients/ts/signalr/README.md
+++ b/src/SignalR/clients/ts/signalr/README.md
@@ -5,6 +5,10 @@ JavaScript and TypeScript clients for SignalR for ASP.NET Core
 ```bash
 npm install @aspnet/signalr
 ```
+or
+```bash
+yarn add @aspnet/signalr
+```
 
 ## Usage
 
diff --git a/src/SignalR/clients/ts/signalr/package.json b/src/SignalR/clients/ts/signalr/package.json
index cb2f600b2b5715da10c8059c5da0cf4d94965553..288d444f2349a48d5b9db2d1ed749fe020827ff2 100644
--- a/src/SignalR/clients/ts/signalr/package.json
+++ b/src/SignalR/clients/ts/signalr/package.json
@@ -39,14 +39,14 @@
     "src/**/*"
   ],
   "devDependencies": {
-    "es6-promise": "^4.2.2",
-    "@types/node": "^10.9.4",
     "@types/eventsource": "^1.0.2",
-    "@types/request": "^2.47.1"
+    "@types/node": "^10.9.4",
+    "@types/request": "^2.47.1",
+    "es6-promise": "^4.2.2"
   },
   "dependencies": {
-    "ws": "^6.0.0",
     "eventsource": "^1.0.7",
-    "request": "^2.88.0"
+    "request": "^2.88.0",
+    "ws": "^6.0.0"
   }
 }
diff --git a/src/SignalR/docs/JSFunctionalTests.md b/src/SignalR/docs/JSFunctionalTests.md
index 27a7392fb44b9163f0867b5be355236143985f32..a7e5a26fd2781edc92e20ca527bbc5080685fa8e 100644
--- a/src/SignalR/docs/JSFunctionalTests.md
+++ b/src/SignalR/docs/JSFunctionalTests.md
@@ -13,7 +13,7 @@ Our JavaScript client functional tests are written using [Jasmine](https://jasmi
 
 ### Iterating
 
-The `npm test` command will take a while, because it will build the `clients\ts\signalr`, `clients\ts\signalr-protocol-msgpack` and `clients\ts\FunctionalTests` folders as well as `dotnet build` the `clients\ts\FunctionalTests` folder (to build the server-side components). If you are making changes, it's nice to be able to build only the things you need to build. To skip all the optional build steps, you can run `npm run test:inner` in `clients\ts\FunctionalTests`. This will skip building `clients\ts\signalr` and `clients\signalr-protocol-msgpack` (it will still build the `clients\ts\FunctionalTests` folder). If you make changes to those libraries, you have to manually build those directories.
+The `npm test` command will take a while, because it will build the `clients\ts\signalr`, `clients\ts\signalr-protocol-msgpack` and `clients\ts\FunctionalTests` folders as well as `dotnet build` the `clients\ts\FunctionalTests` folder (to build the server-side components). If you are making changes, it's nice to be able to build only the things you need to build. To skip all the optional build steps, you can run `yarn run test:inner` in `clients\ts\FunctionalTests`. This will skip building `clients\ts\signalr` and `clients\signalr-protocol-msgpack` (it will still build the `clients\ts\FunctionalTests` folder). If you make changes to those libraries, you have to manually build those directories.
 
 ## Running tests from the browser