Two major ones coming from a .NET background are;
1) dynamic language increases errors and reduces the availability of productivity tools like refactoring and autocompletion
2) duplication of code between the front-end and back-end
These are valid complaints, and do have an impact on productivity. But.
Even in low-latency on-premises intranet environments this model is outdated for all but the simplest of solutions, and with cloud and distributed workforces increasing, the inefficiencies of this approach are becoming more significant.
I am not advocating for Single Page Applications, where a whole raft of additional complexities arise for often minimal realized benefit, but a middle ground is necessary.
So what are some options to increase productivity and produce great web applications?
Rich Server-Side Frameworks
Vaadin and the now-defunct Lightswitch remove the front-end from the development process altogether. The server-side object model or designer tool is used to provide the screen definition, and the HTML is generated based on the server-side definition. The frameworks are usually smart enough to support rich client-side processing as well (without such features, you are really better off with MVC-style solutions with server-side HTML templating engine like ASP.NET MVC/Razor, DJango and Ruby on Rails).
Server-side Frameworks with UI Controls
There are half-assed measures like ASP.NET Content Panels (and most of the ASP.NET Ajax Extensions) and better solutions like ASP.Net MVC unobtrusive validation that allow the server-rendered HTML to also dynamically generate client-side code to provide client-side processing that would otherwise require a postback.
NodeJS proponents tout that a single codebase across front-end and back-end code will improve productivity, and why limit your front-end functionality when you can use that code in the back-end.
A counter argument is that there will always be 'client specific' code and 'server specific' code – yes using a common language means reduced context switching fatigue, and you can share functionality between the front and back-end, but at the end of the day you are still writing code for two separate execution paths – your back-end won't have code that calls the back-end services, but you will certainly need that code in your front-end.
This also emphasises the issues of untyped languages (unless you use something like TypeScript), and you are also removing all the years of .NET expertise in one fell swoop.
I include this as an aside, as it is experimental and very early days, but with the growth of WebAssembly and tools like Blazor, it is possible to build .NET websites that run natively in the client browser.
This doesn't quite work in the way one might expect, rather than incorporating something like ASP.NET MVC in the browser, it uses stand-alone razor-syntax pages defining layout and functionality within the page. In many respects it is a step away from "good architectural separation of concerns" but to some extend does align to component-based web design models like React and Vue, so with a better application state management engine this could work well.
Embracing full-stack development
Treating the client-side as a first-class citizen in your solution doesn't directly address the productivity issues raised, but can indirectly make a dramatic difference.
Elmish and Fable are similar solutions using a functional paradigm (probably a step too far for most developers)
Rather than using code-generation, you can also use and define libraries to consume the back-end services as required. You may use swagger-js to inspect and call your service libraries instead of defining (or generating) a list of URLs and 'fetch()' requests and promises for example.
For validation you might actually create service endpoints that validate an object or field on the server side, and have simple library which performs that validation on the server.
Standardisation and Experience
Obviously the use Code Generation or Boilerplate libraries/functions comes at a development cost, either writing those libraries, or finding good ones and learning how to use them. In the absence of that time, understanding where those solutions apply and appropriately abstracting them is a really good starting point.
For example, annotate all types you WANT to expose to the front-end (if you aren't using a framework that does so automatically). It takes ~10 lines of code to define a custom attribute, and ~20 characters to apply one.
Similarly, abstract your front-end code into specific-purpose libraries with independent configuration (e.g. API libraries with a separate 'root url' defined as a depdency, and separate validation rules from validation execution and field application). This will allow you to start to incorporate functionality later, even if you know you don't have the time or skills to solve those problems to begin with.
With enough team engagement you can bring in things like TypeScript, or UI frameworks like Vue, React or Angular, and beyond that, with dedicated support from your teams you can start to introduce tools and frameworks that can automate a lot of what is required.