I'm working with a client who has a monolithic ASP.NET application as their backend, but also hosts Webpacked JS files for their React.js frontend in the same GIT repo. The obvious problem is that anytime they want to do a frontend release, they have to release and build the entire .NET application along with it, due to the manifest.json
that is in the EC2 instance. The idea is that there will also be many versions over many instances, canaried out to different users, going through various levels of post-production testing, etc., standard DevOps CI/CD pipeline with post-production health checks and automated rollbacks. That is the end goal. In the meantime, they need to split their frontend/backend releases apart, which means separate versioning for both. So after much preamble, the question to the community is two-fold:
Keep in mind that this solution should also expect local development, PR testing, and a blue/green prod setup.
Assuming that you can refactor your project so that the client-side stuff will be a folder of its own, let's call this folder client-{version}, you can create a setting for your project for client-side path, which would be client-v1/ and then, if you need to change v1 -> v2, a command-line command would be needed in order to ensure that this setting can be changed for your project at runtime. So, deploying the client-side would have this algorithm:
I have used following solution, (I learned from JSDelivr, UnPkg ..)
Here is how it works,
/// lets assume this will serve JS/image/css everything from
/// from a path /js-pkg/packageName[@version]/....
[RoutePrefix("js-pkg")]
public class JSContent: Controller {
[HttpGet("{packageName}/{*path}")]
public ActionResult Get(
string packageName,
string path) {
string version = null;
string releasedVersion = db.Versions
.Where(x => x.Package == packageName)
.Select(x => x.Version)
.First();
if (packageName.Contains("@")) {
var tokens = packageName.Split("@");
version = tokens[1];
packageName = tokens[0];
}
if (version == null) {
// this is for performance reason...
// explained in next line...
return Redirect($"/js-pkg/{packageName}@{releasedVersion}/{all}");
}
// since all requests will be versioned...
// you don't have to worry about stale cache ...
Response.CacheControl = "public, max-age=36000000";
// you need to setup a file based locking here
string folder = $"d:\\temp\\{packageName}\\{version}";
if (!System.IO.Directory.Exists(folder))
{
DownloadAndExtract(
$"https://proget...../npm/repo/{package}/-/{package}-{version}.tgz",
folder
);
}
string file = $"{folder}//{path}";
if(!System.IO.File.Exists(file)) {
return HttpNotFound();
}
return File(file);
}
}
Now to host file, you can simply put a CSHTML or view with following line
<script src="/js-pgk/packageName/dist/ui/start.packed.js" ></script>
<link rel="stylesheet" href="/js-pgk/packageName/dist/ui/start.css" ></link>
There are multiple advantages to it,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With