diff --git a/.azure/pipelines/ci.yml b/.azure/pipelines/ci.yml
index 9d806dcc03ab561a01063118bffa45707f772f1e..caa6557d494cac89733aa74286fba7797a653bc9 100644
--- a/.azure/pipelines/ci.yml
+++ b/.azure/pipelines/ci.yml
@@ -29,31 +29,7 @@ variables:
 - ${{ if or(eq(variables['System.TeamProject'], 'public'), in(variables['Build.Reason'], 'PullRequest')) }}:
   - name: _BuildArgs
     value: ''
-
 jobs:
-# Build Web.JS
-- template: jobs/default-build.yml
-  parameters:
-    codeSign: true
-    jobName: WebJS_build
-    jobDisplayName: "Build: Web.JS"
-    agentOs: Linux
-    steps:
-    - script: ./build.sh
-          --ci
-          --projects $(Build.SourcesDirectory)/src/Components/Web.JS/Microsoft.AspNetCore.Components.Web.JS.npmproj
-          -bl:artifacts/log/build.linux-x64.binlog
-          $(_BuildArgs)
-      displayName: Run build.sh
-    - publish: src/Components/Web.JS/dist/
-      artifact: WebJS_Javascript
-    installJdk: false
-    artifacts:
-    - name: WebJS_Logs
-      path: artifacts/log/
-      publishOnError: true
-
-# Code check
 - template: jobs/default-build.yml
   parameters:
     jobName: Code_check
@@ -62,16 +38,10 @@ jobs:
     steps:
     - powershell: ./eng/scripts/CodeCheck.ps1 -ci
       displayName: Run eng/scripts/CodeCheck.ps1
-    artifacts:
-    - name: Code_Check_Logs
-      path: artifacts/log/
-      publishOnError: true
 
 # Build Windows (x64/x86)
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     codeSign: true
     jobName: Windows_build
     jobDisplayName: "Build: Windows x64/x86"
@@ -83,10 +53,6 @@ jobs:
     - script: "echo ##vso[build.addbuildtag]release-candidate"
       condition: and(ne(variables['Build.Reason'], 'PullRequest'), in(variables['DotNetFinalVersionKind'], 'release', 'prerelease'))
       displayName: 'Set CI tags'
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     # !!! NOTE !!! Some of these steps have disabled code signing.
     # This is intentional to workaround https://github.com/dotnet/arcade/issues/1957 which always re-submits for code-signing, even
     # if they have already been signed. This results in slower builds due to re-submitting the same .nupkg many times for signing.
@@ -164,17 +130,10 @@ jobs:
 # Build Windows ARM
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     codeSign: true
     jobName: Windows_arm_build
     jobDisplayName: "Build: Windows ARM"
     agentOs: Windows
-    beforeBuild:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     buildArgs:
       -arch arm
       -sign
@@ -200,16 +159,9 @@ jobs:
 # Build MacOS
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     jobName: MacOs_x64_build
     jobDisplayName: "Build: macOS"
     agentOs: macOs
-    beforeBuild:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     buildArgs:
       --pack
       --all
@@ -219,7 +171,6 @@ jobs:
       -bl:artifacts/log/build.macos.binlog
       $(_BuildArgs)
     installNodeJs: false
-    installJdk: false
     artifacts:
     - name: MacOS_x64_Packages
       path: artifacts/packages/
@@ -237,16 +188,11 @@ jobs:
 # Build Linux x64
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     jobName: Linux_x64_build
     jobDisplayName: "Build: Linux x64"
     agentOs: Linux
+    installNodeJs: false
     steps:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     - script: ./build.sh
           --ci
           --arch x64
@@ -265,7 +211,6 @@ jobs:
           --arch x64 \
           --build-installers \
           --no-build-deps \
-          --no-build-nodejs \
           -p:OnlyPackPlatformSpecificPackages=true \
           -p:BuildRuntimeArchive=false \
           -p:LinuxInstallerType=deb \
@@ -279,15 +224,12 @@ jobs:
           --arch x64 \
           --build-installers \
           --no-build-deps \
-          --no-build-nodejs \
           -p:OnlyPackPlatformSpecificPackages=true \
           -p:BuildRuntimeArchive=false \
           -p:LinuxInstallerType=rpm \
           -bl:artifacts/log/build.rpm.binlog \
           $(_BuildArgs)
       displayName: Build RPM installers
-    installNodeJs: false
-    installJdk: false
     artifacts:
     - name: Linux_x64_Packages
       path: artifacts/packages/
@@ -305,16 +247,9 @@ jobs:
 # Build Linux ARM
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     jobName: Linux_arm_build
     jobDisplayName: "Build: Linux ARM"
     agentOs: Linux
-    beforeBuild:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     buildArgs:
       --arch arm
       --pack
@@ -325,7 +260,6 @@ jobs:
       -bl:artifacts/log/build.linux-arm.binlog
       $(_BuildArgs)
     installNodeJs: false
-    installJdk: false
     artifacts:
     - name: Linux_arm_Packages
       path: artifacts/packages/
@@ -343,16 +277,9 @@ jobs:
 # Build Linux ARM64
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     jobName: Linux_arm64_build
     jobDisplayName: "Build: Linux ARM64"
     agentOs: Linux
-    beforeBuild:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     buildArgs:
       --arch arm64
       --all
@@ -363,7 +290,6 @@ jobs:
       -bl:artifacts/log/build.arm64.binlog
       $(_BuildArgs)
     installNodeJs: false
-    installJdk: false
     artifacts:
     - name: Linux_arm64_Packages
       path: artifacts/packages/
@@ -381,16 +307,9 @@ jobs:
 # Build Linux Musl x64
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     jobName: Linux_musl_x64_build
     jobDisplayName: "Build: Linux Musl x64"
     agentOs: Linux
-    beforeBuild:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     buildScript: ./dockerbuild.sh alpine
     buildArgs:
       --ci
@@ -404,7 +323,6 @@ jobs:
       -bl:artifacts/log/build.musl.binlog
       $(_BuildArgs)
     installNodeJs: false
-    installJdk: false
     artifacts:
     - name: Linux_musl_x64_Packages
       path: artifacts/packages/
@@ -419,19 +337,12 @@ jobs:
   parameters:
     inputName: Linux_musl_x64
 
-# Build Linux Musl ARM64
+# Build Linux Musl arm64
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     jobName: Linux_musl_arm64_build
     jobDisplayName: "Build: Linux Musl ARM64"
     agentOs: Linux
-    beforeBuild:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     buildScript: ./dockerbuild.sh ubuntu-alpine37
     buildArgs:
       --ci
@@ -445,7 +356,6 @@ jobs:
       -bl:artifacts/log/build.musl.binlog
       $(_BuildArgs)
     installNodeJs: false
-    installJdk: false
     artifacts:
     - name: Linux_musl_arm64_Packages
       path: artifacts/packages/
@@ -463,8 +373,6 @@ jobs:
 # Test jobs
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     condition: ne(variables['SkipTests'], 'true')
     jobName: Windows_Test
     jobDisplayName: "Test: Windows Server 2016 x64"
@@ -474,10 +382,6 @@ jobs:
     beforeBuild:
     - powershell: "& ./src/Servers/IIS/tools/UpdateIISExpressCertificate.ps1; & ./src/Servers/IIS/tools/update_schema.ps1"
       displayName: Setup IISExpress test certificates and schema
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     afterBuild:
     - powershell: "& ./build.ps1 -CI -NoBuild -Test /p:RunFlakyTests=true"
       displayName: Run Flaky Tests
@@ -492,18 +396,12 @@ jobs:
 
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     condition: ne(variables['SkipTests'], 'true')
     jobName: Windows_Templates_Test
     jobDisplayName: "Test: Templates - Windows Server 2016 x64"
     agentOs: Windows
     isTestingJob: true
     steps:
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     - script: ./build.cmd -ci -all -pack
       displayName: Build Repo
     - script: ./src/ProjectTemplates/build.cmd -ci -pack -NoRestore -NoBuilddeps "/p:RunTemplateTests=true /bl:artifacts/log/template.pack.binlog"
@@ -520,8 +418,6 @@ jobs:
 
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     condition: ne(variables['SkipTests'], 'true')
     jobName: MacOs_Test
     jobDisplayName: "Test: macOS 10.13"
@@ -531,10 +427,6 @@ jobs:
     beforeBuild:
     - bash: "./eng/scripts/install-nginx-mac.sh"
       displayName: Installing Nginx
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     afterBuild:
     - bash: ./build.sh --ci --pack --no-build --no-restore --no-build-deps "/bl:artifacts/log/packages.pack.binlog"
       displayName: Pack Packages (for Template tests)
@@ -553,8 +445,6 @@ jobs:
 
 - template: jobs/default-build.yml
   parameters:
-    dependsOn:
-    - WebJS_build
     condition: ne(variables['SkipTests'], 'true')
     jobName: Linux_Test
     jobDisplayName: "Test: Ubuntu 16.04 x64"
@@ -566,10 +456,6 @@ jobs:
       displayName: Installing Nginx
     - bash: "echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p"
       displayName: Increase inotify limit
-    - task: DownloadPipelineArtifact@2
-      inputs:
-        artifact: WebJS_Javascript
-        path: $(Build.SourcesDirectory)/src/Components/Web.JS/dist/
     afterBuild:
     - bash: ./build.sh --ci --pack --no-build --no-restore --no-build-deps "/bl:artifacts/log/packages.pack.binlog"
       displayName: Pack Packages (for Template tests)
@@ -603,10 +489,6 @@ jobs:
       chmod +x $HOME/bin/jq
       echo "##vso[task.prependpath]$HOME/bin"
     displayName: Install jq
-  - task: NodeTool@0
-    displayName: Install Node 10.x
-    inputs:
-      versionSpec: 10.x
   - task: UseDotNet@2
     displayName: 'Use .NET Core sdk'
     inputs:
diff --git a/.azure/pipelines/helix-test.yml b/.azure/pipelines/helix-test.yml
index a0ac9427881a4fbb9defb9b53e9b5e6a84cbe919..ed10e8fc2c0b35fd6f4a69d449a4cc4a390e8ab4 100644
--- a/.azure/pipelines/helix-test.yml
+++ b/.azure/pipelines/helix-test.yml
@@ -36,10 +36,11 @@ jobs:
     steps:
     - script: ./restore.sh -ci
       displayName: Restore
-    - script: ./build.sh -ci --arch arm64 -test -projects $(Build.SourcesDirectory)/eng/helix/helix.proj /p:IsHelixJob=true /p:BuildAllProjects=true /p:BuildNative=true -bl
+    - script: ./build.sh -ci --arch arm64 -test --no-build-nodejs -projects $(Build.SourcesDirectory)/eng/helix/helix.proj /p:IsHelixJob=true /p:BuildAllProjects=true /p:BuildNative=true -bl
       displayName: Run build.sh helix arm64 target
       env:
         SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops
+    installNodeJs: false
     artifacts:
     - name: Helix_arm64_logs
       path: artifacts/logs/
diff --git a/build.ps1 b/build.ps1
index 5ba90769c61d91152884121f79f8aa36d01f3f3b..018c3970b759adae331a1f82b99fd600c7169160 100644
--- a/build.ps1
+++ b/build.ps1
@@ -183,7 +183,7 @@ elseif ($Projects) {
 }
 # When adding new sub-group build flags, add them to this check.
 elseif((-not $BuildNative) -and (-not $BuildManaged) -and (-not $BuildNodeJS) -and (-not $BuildInstallers) -and (-not $BuildJava)) {
-    Write-Warning "No default group of projects was specified, so building the 'managed' and its dependent subsets of projects. Run ``build.cmd -help`` for more details."
+    Write-Warning "No default group of projects was specified, so building the 'managed' subsets of projects. Run ``build.cmd -help`` for more details."
 
     # This goal of this is to pick a sensible default for `build.cmd` with zero arguments.
     # Now that we support subfolder invokations of build.cmd, we will be pushing to have build.cmd build everything (-all) by default
@@ -191,10 +191,6 @@ elseif((-not $BuildNative) -and (-not $BuildManaged) -and (-not $BuildNodeJS) -a
     $BuildManaged = $true
 }
 
-if ($BuildManaged -and ($NoBuildNodeJS)) {
-    Write-Warning "Some managed projects that depend on NodeJS projects will be skipped since building NodeJS is disabled."
-}
-
 if ($BuildInstallers) { $MSBuildArguments += "/p:BuildInstallers=true" }
 if ($BuildManaged) { $MSBuildArguments += "/p:BuildManaged=true" }
 if ($BuildNative) { $MSBuildArguments += "/p:BuildNative=true" }
diff --git a/build.sh b/build.sh
index 24a112ddbc5dfbf139ea0bf0df677aee55005bc9..c170ac1844cae1f14d4fc7d024dbbccba0f37374 100755
--- a/build.sh
+++ b/build.sh
@@ -213,7 +213,7 @@ elif [ ! -z "$build_projects" ]; then
 elif [ -z "$build_managed" ] && [ -z "$build_nodejs" ] && [ -z "$build_java" ] && [ -z "$build_native" ] && [ -z "$build_installers" ]; then
     # This goal of this is to pick a sensible default for `build.sh` with zero arguments.
     # We believe the most common thing our contributors will work on is C#, so if no other build group was picked, build the C# projects.
-    __warn "No default group of projects was specified, so building the 'managed' and its dependent subset of projects. Run ``build.sh --help`` for more details."
+    __warn "No default group of projects was specified, so building the 'managed' subset of projects. Run ``build.sh --help`` for more details."
     build_managed=true
 fi
 
@@ -221,10 +221,6 @@ if [ "$build_deps" = false ]; then
     msbuild_args[${#msbuild_args[*]}]="-p:BuildProjectReferences=false"
 fi
 
-if [ "$build_nodejs" = false ] && [ "$build_managed" = true ]; then
-    __warn "Some managed projects that depend on NodeJS projects will be skipped since building NodeJS is disabled."
-fi
-
 # Only set these MSBuild properties if they were explicitly set by build parameters.
 [ ! -z "$build_java" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildJava=$build_java"
 [ ! -z "$build_native" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildNative=$build_native"
diff --git a/docs/BuildFromSource.md b/docs/BuildFromSource.md
index 97a4d0de72bac8fefc28486112b5213a27b3588f..53938c189b62c45b47d2eacbc206cce6a2dd6afc 100644
--- a/docs/BuildFromSource.md
+++ b/docs/BuildFromSource.md
@@ -138,8 +138,6 @@ On macOS/Linux:
 ./build.sh
 ```
 
-By default, all of the C# projects are built. Some C# projects requires NodeJS to be installed to compile JavaScript assets. To disable building NodeJS projects and all C# projects that depend on them, specify /p:BuildNodeJs=false on the command line.
-
 ### Using `dotnet` on command line in this repo
 
 Because we are using pre-release versions of .NET Core, you have to set a handful of environment variables
diff --git a/eng/Build.props b/eng/Build.props
index 40149e613b17b29666092fde12a281b46aa33b0e..eba7a2ac911a33e474c86a28f4a5e429bedc88fb 100644
--- a/eng/Build.props
+++ b/eng/Build.props
@@ -4,16 +4,14 @@
   </PropertyGroup>
 
   <PropertyGroup Condition=" '$(BuildAllProjects)' == 'true' ">
-    <BuildNative Condition="'$(BuildNative)' == ''">true</BuildNative>
-    <BuildManaged Condition="'$(BuildManaged)' == ''">true</BuildManaged>
-    <BuildNodeJS Condition="'$(BuildNodeJS)' == ''">true</BuildNodeJS>
-    <BuildJava Condition="'$(BuildJava)' == ''">true</BuildJava>
+    <BuildNative>true</BuildNative>
+    <BuildManaged>true</BuildManaged>
+    <BuildNodeJS>true</BuildNodeJS>
+    <BuildJava>true</BuildJava>
   </PropertyGroup>
 
   <!-- These projects are always excluded, even when -projects is specified on command line. -->
   <ItemGroup>
-    <!-- Explicitly excluded projects -->
-    <ProjectToExclude Include="$(ProjectToExclude)" />
 
     <!-- These projects use 'legacy' csproj, which is not supported by dotnet-msbuild. -->
     <ProjectToExclude Include="
@@ -33,7 +31,6 @@
                       $(RepoRoot)src\submodules\**\*.*proj;
                       $(RepoRoot)src\Installers\**\*.*proj;
                       $(RepoRoot)src\SignalR\clients\ts\**\node_modules\**\*.*proj;
-                      $(RepoRoot)src\Components\Web.JS\node_modules\**\*.*proj;
                       $(RepoRoot)src\Components\Blazor\Templates\src\content\**\*.*proj;
                       $(RepoRoot)src\ProjectTemplates\Web.ProjectTemplates\content\**\*.csproj;
                       $(RepoRoot)src\ProjectTemplates\Web.ProjectTemplates\content\**\*.fsproj;
@@ -46,6 +43,7 @@
                       $(RepoRoot)src\Servers\Kestrel\perf\PlatformBenchmarks\**\*.csproj;
                       $(RepoRoot)src\SignalR\perf\benchmarkapps\**\*.csproj;
                       " />
+
   </ItemGroup>
 
   <Choose>
@@ -104,7 +102,6 @@
         <ProjectToExclude Condition=" '$(BuildNative)' != 'true'" Include="@(NativeProjects)" />
 
         <NodeJsProjects Include="
-                          $(RepoRoot)src\Components\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj;
                           $(RepoRoot)src\SignalR\**\*.npmproj;
                           $(RepoRoot)src\Middleware\**\*.npmproj;
                           "
@@ -120,17 +117,6 @@
         <ProjectToBuild Condition=" '$(BuildJava)' == 'true'" Include="@(JavaProjects)" Exclude="@(ProjectToExclude)" />
         <ProjectToExclude Condition=" '$(BuildJava)' != 'true'" Include="@(JavaProjects)" />
 
-        <!-- These projects have a transitive dependency on Microsoft.AspNetCore.Components.Web.JS. Exclude these projects if we are not building NodeJS -->
-        <!-- Do not skip these projects on the CI since we don't want to accidentally miss building artifacts -->
-        <DotnetProjectsTransitiveNodeJsDependencies Include="
-                          $(RepoRoot)src\Framework\**\*.csproj;
-                          $(RepoRoot)src\Analyzers\Analyzers\test\Microsoft.AspNetCore.Analyzers.Test.csproj;
-                          $(RepoRoot)src\ProjectTemplates\*\*.csproj;
-                          $(RepoRoot)src\ProjectTemplates\testassets\*\*.csproj;
-                          $(RepoRoot)src\Components\**\*.*proj;
-                          $(RepoRoot)src\Mvc\**\*.*proj;" />
-        <ProjectToExclude Include="@(DotnetProjectsTransitiveNodeJsDependencies)" Condition="'$(BuildNodeJS)' == 'false' and '$(ContinuousIntegrationBuild)' != 'true'" />
-
         <!--
           Use caution to avoid deep recursion. If the globbing pattern picks up something which exceeds MAX_PATH,
           the entire pattern will silently fail to evaluate correctly.
diff --git a/eng/scripts/CodeCheck.ps1 b/eng/scripts/CodeCheck.ps1
index 5ed823f08311979e6ae32c61151c3335a637c224..669b56c21f5f5ea72972e888fdbd10f95ceb014f 100644
--- a/eng/scripts/CodeCheck.ps1
+++ b/eng/scripts/CodeCheck.ps1
@@ -166,6 +166,11 @@ try {
         & dotnet run -p "$repoRoot/eng/tools/BaselineGenerator/"
     }
 
+    Write-Host "Re-generating Web.JS files"
+    Invoke-Block {
+        & dotnet build "$repoRoot\src\Components\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
+    }
+
     Write-Host "Run git diff to check for pending changes"
 
     # Redirect stderr to stdout because PowerShell does not consistently handle output to stderr
diff --git a/eng/targets/Npm.Common.targets b/eng/targets/Npm.Common.targets
index 204e14d01f5c50f441e96138a6ca4cf8b89f83ff..c290e39756647bf2568e058dcfc848d7de9268b8 100644
--- a/eng/targets/Npm.Common.targets
+++ b/eng/targets/Npm.Common.targets
@@ -11,28 +11,15 @@
     <IntermediateOutputPath>$([MSBuild]::NormalizeDirectory('$(BaseIntermediateOutputPath)'))$(Configuration)\</IntermediateOutputPath>
     <InstallArgs Condition="'$(RestoreLockedMode)' == 'true'">--frozen-lockfile</InstallArgs>
     <_BackupPackageJson>$(IntermediateOutputPath)$(MSBuildProjectName).package.json.bak</_BackupPackageJson>
-    <BuildDependsOn>
-      PrepareForBuild;
-      ResolveProjectReferences;
-      _Build;
-    </BuildDependsOn>
-    <NpmBuildArgs Condition="'$(NpmBuildArgs)' == ''">run build</NpmBuildArgs>
   </PropertyGroup>
 
   <ItemGroup>
     <TSFiles Include="$(MSBuildProjectDirectory)\*\*.ts" />
     <TSFiles Include="$(MSBuildProjectDirectory)\package.json" />
-    <TSFiles Include="$(MSBuildProjectDirectory)\*.npmproj" />
   </ItemGroup>
 
   <Target Name="_CheckForInvalidConfiguration">
     <Error Text="Missing expected property: PackageId" Condition="'$(IsPackable)' != 'false' and '$(PackageId)' == ''" />
-
-    <Exec ContinueOnError="true" Command="node -v">
-       <Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
-    </Exec>
-
-    <Error Text="Building *.npmproj but NodeJS was not detected on path. Ensure NodeJS is on path or disable building NodeJS projects with /p:BuildNodeJs=false. Skipping NodeJS projects will also skip managed projects depending on them, including Components, Mvc and Analysers." Condition="'$(ErrorCode)' != '0'"/>
   </Target>
 
   <Target Name="Restore">
@@ -49,13 +36,13 @@
              BuildInParallel="true" />
   </Target>
 
-  <Target Name="Build" DependsOnTargets="$(BuildDependsOn)" />
+  <Target Name="Build" DependsOnTargets="PrepareForBuild;ResolveProjectReferences;_Build" />
 
   <Target Name="_Build"
     Condition="'$(IsBuildable)' != 'false'"
     Inputs="@(TSFiles)"
     Outputs="$(BaseIntermediateOutputPath)\build-sentinel" >
-    <Yarn Command="$(NpmBuildArgs)" StandardOutputImportance="High" StandardErrorImportance="High" />
+    <Yarn Command="run build" StandardOutputImportance="High" StandardErrorImportance="High" />
     <WriteLinesToFile Overwrite="true" File="$(BaseIntermediateOutputPath)\build-sentinel" />
   </Target>
 
diff --git a/src/Components/Blazor/testassets/MonoSanityClient/MonoSanityClient.csproj b/src/Components/Blazor/testassets/MonoSanityClient/MonoSanityClient.csproj
index b186c391941bdef3ca602dcfcaaafd8773c1c7e5..e40ea493bd9c8dd7cc047dabadcd75bcccd93513 100644
--- a/src/Components/Blazor/testassets/MonoSanityClient/MonoSanityClient.csproj
+++ b/src/Components/Blazor/testassets/MonoSanityClient/MonoSanityClient.csproj
@@ -11,4 +11,7 @@
     <!-- loader.js is hard-coded to assume it can load .pdbs regardless of Debug/Release configuration -->
     <BlazorEnableDebugging>true</BlazorEnableDebugging>
   </PropertyGroup>
+
+  <ItemGroup>
+  </ItemGroup>
 </Project>
diff --git a/src/Components/Directory.Build.targets b/src/Components/Directory.Build.targets
index 7afb3dc46f3c80321e1c064655e20079fe2fe280..bd6e40582964968a77b73afde877a8e0150dcdcd 100644
--- a/src/Components/Directory.Build.targets
+++ b/src/Components/Directory.Build.targets
@@ -5,16 +5,6 @@
 
   <ItemGroup>
     <None Include="$(MSBuildThisFileDirectory)THIRD-PARTY-NOTICES.txt" Pack="true" PackagePath="." />
-
-    <!-- Add a project dependency without reference output assemblies to enforce build order -->
-    <!-- Applying workaround for https://github.com/microsoft/msbuild/issues/2661 and https://github.com/dotnet/sdk/issues/952 -->
-    <ProjectReference
-      Condition="'$(ReferenceBlazorBuildLocally)' == 'true' and '$(BuildNodeJS)' != 'false'"
-      Include="$(RepoRoot)src\Components\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
-      ReferenceOutputAssemblies="false"
-      SkipGetTargetFrameworkProperties="true"
-      UndefineProperties="TargetFramework"
-      Private="false" />
   </ItemGroup>
 
   <Import Project="Blazor\Build\src\ReferenceFromSource.props" Condition="'$(ReferenceBlazorBuildLocally)' == 'true'" />
diff --git a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
index bb6b9777eae7f9dd9fce0aec5115b4293c0d59f8..ffa9a5ffb401f3dee4c482765b3fd750ce64eed5 100644
--- a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
+++ b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
@@ -20,16 +20,6 @@
     <Reference Include="Microsoft.Extensions.Caching.Memory" />
     <Reference Include="Microsoft.Extensions.FileProviders.Composite" />
     <Reference Include="Microsoft.Extensions.FileProviders.Embedded" />
-
-    <!-- Add a project dependency without reference output assemblies to enforce build order -->
-    <!-- Applying workaround for https://github.com/microsoft/msbuild/issues/2661 and https://github.com/dotnet/sdk/issues/952 -->
-    <ProjectReference
-      Include="..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
-      ReferenceOutputAssemblies="false"
-      SkipGetTargetFrameworkProperties="true"
-      UndefineProperties="TargetFramework"
-      Private="false"
-      Condition="'$(BuildNodeJS)' != 'false'" />
   </ItemGroup>
 
   <PropertyGroup>
@@ -62,7 +52,12 @@
   </ItemGroup>
 
   <PropertyGroup>
-    <BlazorServerJSFile>..\..\Web.JS\dist\$(Configuration)\blazor.server.js</BlazorServerJSFile>
+    <!--
+      We check in the Release / Production build of blazor.*.js, but not the Debug builds. Consequently the former is always available to embed, the latter is only available
+      if Web.JS was built locally. Use the Debug build when available and building in Debug configuration.
+    -->
+    <BlazorServerJSFile>..\..\Web.JS\dist\Release\blazor.server.js</BlazorServerJSFile>
+    <BlazorServerJSFile Condition="'$(Configuration)' == 'Debug' AND Exists('..\..\Web.JS\dist\Debug\blazor.server.js')">..\..\Web.JS\dist\Debug\blazor.server.js</BlazorServerJSFile>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/src/Components/Web.JS/.gitignore b/src/Components/Web.JS/.gitignore
index afce87ca650e7b0bf389154fac63790bd0687759..10999e07926c0c2ba0540fad63ecbddac75649dd 100644
--- a/src/Components/Web.JS/.gitignore
+++ b/src/Components/Web.JS/.gitignore
@@ -1,2 +1,2 @@
 node_modules/
-dist/
+dist/Debug/
diff --git a/src/Components/Web.JS/Microsoft.AspNetCore.Components.Web.JS.npmproj b/src/Components/Web.JS/Microsoft.AspNetCore.Components.Web.JS.npmproj
index 8e0a17ece09e028f65c0c3b72079527d981d10c4..f47ada3d4fdf42de5e95e77d67f518b48dc1ee67 100644
--- a/src/Components/Web.JS/Microsoft.AspNetCore.Components.Web.JS.npmproj
+++ b/src/Components/Web.JS/Microsoft.AspNetCore.Components.Web.JS.npmproj
@@ -7,18 +7,8 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference
-      Include="..\..\SignalR\clients\ts\signalr\signalr.npmproj"
-      ReferenceOutputAssemblies="false"
-      SkipGetTargetFrameworkProperties="true"
-      UndefineProperties="TargetFramework"
-      Private="false" />
-    <ProjectReference
-      Include="..\..\SignalR\clients\ts\signalr-protocol-msgpack\signalr-protocol-msgpack.npmproj"
-      ReferenceOutputAssemblies="false"
-      SkipGetTargetFrameworkProperties="true"
-      UndefineProperties="TargetFramework"
-      Private="false" />
+    <ProjectReference Include="..\..\SignalR\clients\ts\signalr\signalr.npmproj" />
+    <ProjectReference Include="..\..\SignalR\clients\ts\signalr-protocol-msgpack\signalr-protocol-msgpack.npmproj" />
   </ItemGroup>
 
   <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Directory.Build.targets))\Directory.Build.targets" />
diff --git a/src/Components/Web.JS/dist/.gitattributes b/src/Components/Web.JS/dist/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..8935dff0d325f67428198e8cac1eba9c4d65c459
--- /dev/null
+++ b/src/Components/Web.JS/dist/.gitattributes
@@ -0,0 +1,3 @@
+# Prevent generated files from showing up in git and GitHub diffs. See https://www.git-scm.com/docs/gitattributes#_defining_macro_attributes, https://github.com/github/linguist#generated-code
+*.js    -diff -merge
+*.js    linguist-generated=true
diff --git a/src/Components/Web.JS/dist/Release/blazor.server.js b/src/Components/Web.JS/dist/Release/blazor.server.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f9b325d4e3794bbbf84853d5dd55def87cf1200
Binary files /dev/null and b/src/Components/Web.JS/dist/Release/blazor.server.js differ
diff --git a/src/Components/Web.JS/dist/Release/blazor.webassembly.js b/src/Components/Web.JS/dist/Release/blazor.webassembly.js
new file mode 100644
index 0000000000000000000000000000000000000000..e55ca73676ee02b3a7db602bfbf3686ae560e296
Binary files /dev/null and b/src/Components/Web.JS/dist/Release/blazor.webassembly.js differ
diff --git a/src/Components/Web.JS/package.json b/src/Components/Web.JS/package.json
index 3426f96fd5a0c3ac874b22f3d1301b0d7a79b442..ea59361494aae7c9688032359891741ef5b115b9 100644
--- a/src/Components/Web.JS/package.json
+++ b/src/Components/Web.JS/package.json
@@ -5,12 +5,9 @@
   "description": "",
   "main": "index.js",
   "scripts": {
-    "preclean": "yarn install --mutex network",
-    "clean": "node node_modules/rimraf/bin.js ./dist",
-    "prebuild": "yarn run clean && yarn install --mutex network",
     "build": "yarn run build:debug && yarn run build:production",
-    "build:debug": "cd src && node ../node_modules/webpack-cli/bin/cli.js --mode development --config ./webpack.config.js",
-    "build:production": "cd src && node ../node_modules/webpack-cli/bin/cli.js --mode production --config ./webpack.config.js",
+    "build:debug": "cd src && webpack --mode development --config ./webpack.config.js",
+    "build:production": "cd src && webpack --mode production --config ./webpack.config.js",
     "test": "jest"
   },
   "devDependencies": {
@@ -24,7 +21,6 @@
     "@typescript-eslint/parser": "^1.5.0",
     "eslint": "^5.16.0",
     "jest": "^24.8.0",
-    "rimraf": "^2.6.2",
     "ts-jest": "^24.0.0",
     "ts-loader": "^4.4.1",
     "typescript": "^3.5.3",
diff --git a/src/Components/Web.JS/tests/DefaultReconnectionHandler.test.ts b/src/Components/Web.JS/tests/DefaultReconnectionHandler.test.ts
index d59e0fecfe38fb0409fa0ccce0d6c3ff5d739298..62f207415e363aac7178d8b45af7902bcb6db848 100644
--- a/src/Components/Web.JS/tests/DefaultReconnectionHandler.test.ts
+++ b/src/Components/Web.JS/tests/DefaultReconnectionHandler.test.ts
@@ -58,24 +58,23 @@ describe('DefaultReconnectionHandler', () => {
     expect(reconnect).toHaveBeenCalledTimes(1);
   });
 
-  // Skipped while under investigation: https://github.com/aspnet/AspNetCore/issues/12578
-  // it('invokes failed if reconnect fails', async () => {
-  //   const testDisplay = createTestDisplay();
-  //   const reconnect = jest.fn().mockRejectedValue(null);
-  //   const handler = new DefaultReconnectionHandler(NullLogger.instance, testDisplay, reconnect);
-  //   window.console.error = jest.fn();
-
-  //   handler.onConnectionDown({
-  //     maxRetries: 3,
-  //     retryIntervalMilliseconds: 20,
-  //     dialogId: 'ignored'
-  //   });
-
-  //   await delay(500);
-  //   expect(testDisplay.show).toHaveBeenCalled();
-  //   expect(testDisplay.failed).toHaveBeenCalled();
-  //   expect(reconnect).toHaveBeenCalledTimes(3);
-  // });
+  it('invokes failed if reconnect fails', async () => {
+    const testDisplay = createTestDisplay();
+    const reconnect = jest.fn().mockRejectedValue(null);
+    const handler = new DefaultReconnectionHandler(NullLogger.instance, testDisplay, reconnect);
+    window.console.error = jest.fn();
+
+    handler.onConnectionDown({
+      maxRetries: 3,
+      retryIntervalMilliseconds: 20,
+      dialogId: 'ignored'
+    });
+
+    await delay(100);
+    expect(testDisplay.show).toHaveBeenCalled();
+    expect(testDisplay.failed).toHaveBeenCalled();
+    expect(reconnect).toHaveBeenCalledTimes(3);
+  });
 });
 
 function attachUserSpecifiedUI(options: ReconnectionOptions): Element {
diff --git a/src/Components/Web.JS/yarn.lock b/src/Components/Web.JS/yarn.lock
index 48b8058558632ad7f2e94d52653615a735765733..f49df8df7dd4ef1abb2c99a077b64f768ee8bea2 100644
--- a/src/Components/Web.JS/yarn.lock
+++ b/src/Components/Web.JS/yarn.lock
@@ -2141,7 +2141,7 @@ glob-parent@^3.1.0:
     is-glob "^3.1.0"
     path-dirname "^1.0.0"
 
-glob@^7.1.1, glob@^7.1.2:
+glob@^7.1.1, glob@^7.1.2, glob@^7.1.3:
   version "7.1.3"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
   integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
@@ -2153,18 +2153,6 @@ glob@^7.1.1, glob@^7.1.2:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@^7.1.3:
-  version "7.1.4"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
-  integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
-  dependencies:
-    fs.realpath "^1.0.0"
-    inflight "^1.0.4"
-    inherits "2"
-    minimatch "^3.0.4"
-    once "^1.3.0"
-    path-is-absolute "^1.0.0"
-
 global-modules@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
@@ -2414,21 +2402,16 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
-  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
 
 inherits@2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
   integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
 
-inherits@2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
 ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
diff --git a/src/Shared/E2ETesting/E2ETesting.targets b/src/Shared/E2ETesting/E2ETesting.targets
index 48d8dad7a6562853981ae51e9ae0e7ffb9ba0cce..fb3c80a3a3813801aa91031d3b0af447cd2a7baf 100644
--- a/src/Shared/E2ETesting/E2ETesting.targets
+++ b/src/Shared/E2ETesting/E2ETesting.targets
@@ -11,7 +11,7 @@
       Importance="High"
       Text="Prerequisites were not enforced at build time. Running Yarn or the E2E tests might fail as a result. Check /src/Shared/E2ETesting/Readme.md for instructions." />
 
-    <Yarn Command="install --mutex network" Condition="'$(EnforceE2ETestPrerequisites)' == 'true'"/>
+    <Yarn Command="install --mutex network" />
   </Target>
 
   <Target
diff --git a/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj b/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj
index f80aec5ee804667e1973d8ac31f323f7e42226e4..f75f288f9aaec5256db5442009170e3213886ad9 100644
--- a/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj
+++ b/src/SignalR/clients/ts/FunctionalTests/SignalR.Npm.FunctionalTests.npmproj
@@ -8,7 +8,6 @@
     <_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:inner --no-color --configuration $(Configuration)</NpmTestArgs>
-    <NpmBuildArgs>run build:inner</NpmBuildArgs>
   </PropertyGroup>
 
   <ItemGroup>