Another option if you are using a NodeJS backend is to write a node module that contains just the validation logic, and then share that amongst the SPA and backend. Only gotcha is it cannot include anything you wouldn't want bundled into your UI code.
At my first PHP job we used #2 from list pretty successfully, the only thing that sucked was translating the validation errors back into the UI, but I think that can be improved easily by modern UI frameworks (this was a jQuery app at the time).
Another option if you are using a NodeJS backend is to write a node module that contains just the validation logic, and then share that amongst the SPA and backend. Only gotcha is it cannot include anything you wouldn't want bundled into your UI code.
At my first PHP job we used #2 from list pretty successfully, the only thing that sucked was translating the validation errors back into the UI, but I think that can be improved easily by modern UI frameworks (this was a jQuery app at the time).