A common way to handle this is via grunt tasks, which copy the relevant files out of node_modules, into a more appropriate folder.
This is an excerpt from a copy task which I used for a recent project...
copy: {
types: {
files: [
{
expand: true,
cwd: 'node_modules/@types',
src: ['**/*.ts'],
dest: 'scripts/typings'
}
]
},
jquery: {
files: [
{
expand: true,
cwd: 'node_modules/jquery/dist',
src: ['*.js'],
dest: 'Content/libraries/jquery'
}
]
},
handlebars: {
files: [
{
expand: true,
cwd: 'node_modules/handlebars/dist',
src: ['*.js'],
dest: 'Content/libraries/handlebars'
}
]
},
bootstrap: {
files: [
{
expand: true,
cwd: 'node_modules/bootstrap',
src: ['dist/js/*.js', 'dist/fonts/*.*', 'dist/css/*.css'],
dest: 'Content/libraries/bootstrap'
}
]
}
}
There may be more succinct ways to write this, but it works for me.
This allows me to update my website packages by doing the following...
$ npm install
$ grunt copy
The folders /Content/libraries, and /scripts/typings are committed to my application git repo, node_modules isn't. This helps prevent issues if a module become unavailable at some stage in the future. My git repo contains everything required for the site to function.
If for some reason one of these modules was removed from npm, it would just mean I couldn't do upgrades, but my site will still work with the files that my git repo includes.
In my case, I don't actually need node_modules at all in my runtime environment, as I'm not using nodejs. I'm just using npm to manage my application's client-side module dependencies.