Reputation: 91608
I have a fairly simple web application based on the Visual Studio "React" template. When I run MSBuild, it runs an npm install
and then calls webpack
to create a Javascript bundle. When I build this locally, the app runs fine. When I build this in a DevOps pipeline, the home page is a blank white page with script errors in the console:
I doubt the error really matters much and I wouldn't even begin to know where to start tracking it down anyway. However, after quite a bit of investigation here's what I know so far:
package.json
and package-lock.json
are exactly the same.node_modules
directory locally and on DevOps. Every single file in every single directory is exactly the same. I'm npm install
ing the same exact versions of everything.node 12.10.0
Here's my package.json
file:
{
"name": "LimeadeDocs",
"version": "0.1.0",
"private": true,
"dependencies": {
"bootstrap": "^3.4.1",
"core-js": "^3.1.4",
"js-yaml": "^3.13.1",
"mobx": "^5.13.0",
"mobx-react": "^6.1.3",
"react": "^16.9.0",
"react-bootstrap": "^0.31.5",
"react-dom": "^16.9.0",
"react-is": "^16.9.0",
"react-router-bootstrap": "^0.24.4",
"react-router-dom": "^4.2.2",
"react-scripts": "1.0.17",
"redoc": "2.0.0-rc.14",
"rimraf": "^2.6.2",
"styled-components": "^4.4.0",
"swagger-diff": "^0.6.0"
},
"scripts": {
"start": "rimraf ./build && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
Here's my DevOps build pipeline:
trigger:
- master
pool:
vmImage: 'windows-latest'
variables:
buildConfiguration: 'Debug'
steps:
- task: UseNode@1
displayName: 'Install Node 12.10.0'
inputs:
version: '12.10.0'
- task: NuGetCommand@2
displayName: 'Restore NuGet Packages'
inputs:
command: 'restore'
restoreSolution: './LimeadeDocs.sln'
- task: MSBuild@1
inputs:
solution: './LimeadeDocs.sln'
platform: 'Any CPU'
configuration: '$(BuildConfiguration)'
msbuildArguments: '/t:publish'
- task: PublishBuildArtifacts@1
displayName: 'Publish Build Artifacts'
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/LimeadeDocs/bin/$(BuildConfiguration)/netcoreapp2.1/publish/'
ArtifactName: 'Website'
condition: succeededOrFailed()
Here's the CSPROJ file it's building:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<!-- Don't publish the SPA source files, but do show them in the project files list -->
<Content Remove="$(SpaRoot)**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)build\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
So, in summary, if I run msbuild .\LimeadeDocs.sln /t:publish
from my command line, zip up the contents of \bin\Debug\netcoreapp2.1\publish
and drop it on the web server, it works. However, when I deploy the contents of the Website artifact built in DevOps, I get the script error.
I also ran a diff between the bundle.js file produced locally and the one DevOps produces. There's massive amounts of differences, so I'm not quite sure what would account for that. Originally, it looked like different versions of packages were getting installed locally than on DevOps, but I've done everything I can think of to show that isn't the case. So, the bundling mechanism that takes all these packages and builds a giant bundle.js file must be running differently on DevOps as it does locally. However, it's all the same code. I'm pretty stuck as to where to go from here.
Upvotes: 1
Views: 1002
Reputation: 91608
So, turns out the answer was to remove the package-lock.json
file from the build so that the DevOps build agent has to generate the file itself. No idea what sort of environmental differences there are between my local build machine and the DevOps agent, but it seems the two files are incompatible and thus cannot be checked in to Git.
Hopefully this will help someone in the future who has run across this problem too.
Upvotes: 2