How to provide usage information for npm scripts - npm

Is there an easy way to provide usage information for npm scripts?
Ideally, when I run npm run, I would get output like this (note the description at bottom of each task):
Lifecycle scripts included in product-discovery-service:
start
node server.js
available via `npm run-script`:
watch
run-p watch:build watch:run
Run in development mode and rebuild/restart when changes are made
watch:build
npm run build:dev -- --watch
Probably don't need this (would be nice to be able to omit tasks like this)
watch:run
nodemon --watch build/ --inspect
Probably don't need this (would be nice to be able to omit tasks like this)
prewatch:run
wait-on --log build/server.js
Probably don't need this (would be nice to be able to omit tasks like this)
build
babel server.js --out-dir build/
Build the project
prebuild
rimraf build/
Probably don't need this (would be nice to be able to omit tasks like this)
build:dev
npm run build -- --source-maps
Probably don't need this (would be nice to be able to omit tasks like this)
It looks like npm doesn't support this, but maybe there's a third-party with a solution? I found npm-scripts-help, but it feels clunky.

Short Answer:
Yes you're correct, npm does not provide a built-in feature to include descriptions when running npm run. So, any solution you choose will have some level of "feels clunky" associated with it.
As you've mentioned
npm-scripts-help is a package which can achieve this. I'm not aware of other similar third-party solutions.
Alternative custom solution:
The following steps describe how to write a simple custom Nodejs utility script (without using another third-party package dependency). This script can then be invoked via npm-scripts.
Create a simple Nodejs utility script as follows. Lets name the file usage.js.
usage.js
const usage = `
Lifecycle scripts included in ${process.env.npm_package_name}:
start
node server.js
available via \`npm run-script\`:
watch
run-p watch:build watch:run
Run in development mode and rebuild/restart when changes are made
watch:build
npm run build:dev -- --watch
Probably don't need this (would be nice to be able to omit tasks like this)
watch:run
nodemon --watch build/ --inspect
...`
console.log('%s', usage);
Save usage.js in your projects root directory at the same level where package.json is stored.
Add the following usage script to the scripts section of your package.json:
...
"scripts": {
"usage": "node usage",
...
},
...
Run npm run usage to print the usage info to the console. A script name (i.e. usage) has to be provided with npm run. Unfortunately your ideal of just running npm run will only log npm's simple log - which doesn't include descriptions.
Notes:
On line two in usage.js we reference the package name variable via the part which reads: ${process.env.npm_package_name}
If you change the location of where usage.json is stored in your project directory you'll need to redifine the path to it in your npm-script as required. For example, if you choose to store it in a folder named scripts, which resides in your projects root directory, then your usage script should be defined as follows:
...
"scripts": {
"usage": "node scripts/usage",
...
},
...
Adding ANSI/VT100 Control sequences
You can utilize ANSI/VT100 Control sequences in usage.js to add colors and formatting to the usage log.
For example, in the following usage.js, the codes:
\x1b[1m
\x1b[0m
...are utilized to embolden code snippets and reset the formatting back to default respectively.
Tip: If cross-platform is a requirement I suggest using the ANSI 8/16 Colors (listed at the previous link) only. The formatting codes for bold (\x1b[1m) do not work in Windows cmd.exe using terminals such as Windows Command Prompt or PowerShell.
usage.js (with formatting)
const BOLD = '\x1b[1m';
const NORM = '\x1b[0m';
const formattedUsage = `
Lifecycle scripts included in ${BOLD}${process.env.npm_package_name}:${NORM}
${BOLD}start
node server.js${NORM}
available via ${BOLD}npm run-script${NORM}
${BOLD}watch
run-p watch:build watch:run${NORM}
Run in development mode and rebuild/restart when changes are made
${BOLD}watch:build
npm run build:dev -- --watch${NORM}
...`
console.log('%s', formattedUsage);
You could also consider combining ES6 Template Literals with process.env and package.json vars to reference the values of each npm-script. For example:
`${BOLD}${process.env.npm_package_scripts_watch}:${NORM}`

Related

How to get the version of a remote npm package using a bin script

I'm trying to set up an npx script to create a template project.
In package.json I have:
"bin": {
"init": "bin/init"
}
In the init script I'm using tag='v'$(npm pkg get version | tr -d '"') to get the version of the package. I then use git clone --depth 1 --branch $tag https://github.com/matriarx/typescript.git to clone that specific repository for that specific tag.
When I do yarn link and try use it locally, from within that specific project, it works because it's able to correctly pick up the package.json version. So the above only works if it's run inside an existing project. However that's not what I want to do.
I want to enable someone to run it even if they have nothing locally, by simply doing npx #matriarx/typescript init and it should create the new project by cloning it. More than that I want them to be able to clone any specific version by using npx #matriarx/typescript#0.0.1 init in order to clone a specific version.
However it seems that anything I try is only able to get the version from a local package.json that already exists.
I could just clone the current existing repository without specifying any tag, but that would defeat the point of having releases, then it would just clone any current code completely disregarding the release. So it has to clone the tagged release.
How can I get the remote package version stored on npm from the bin script without having anything locally before hand?
Alternatively is there a better way to do what I'm trying to do?
EDIT: I ended up just hardcoding the version in the script, which works but it sucks because it's tedious to have to update it every time I bump the version. Though for now I still don't know a better way to do it.
After some more time messing around I figured out there is a standard way of doing it, at least since npm 7.
If you have a project like example then you can create a completely separate project called create-example with a bin script.
When you use npm init example, npm will automatically search for a package prefixed with "create-" and execute its main bin script. So when running npm init example it will search for that create-example package and execute the bin script, which will install the example package.
This is how most of the bigger packages like react and next do it.
This approach comes with some disadvantages that I really don't like, for example it will show the incorrect dependencies on npm and it will cause you to have to maintain multiple projects and semvers on different projects. However it will also allow you to create a clean separation between the actual project and the installation of that project.
For some projects it might also make a lot more sense. For example if you have a project that doesn't have a package.json at all and you want to create a setup for it, it wouldn't make sense to create an npm package inside that project just for that. Instead you can create a separate "create-project" package just to set it up and keep npm out of the actual project. In other words it gives you a neat way to create bin scripts for a completely separate project that doesn't have anything to do with npm.
You could also just have created a normal shell script and execute it using curl but I guess npm just gives you another way to do it.
You still have to hardcode the version in that "create-project" package, I still have not seen a way to automatically determine the version from a remote package. The only way I've managed to do that is to completely download the package, get the version, then delete it, but that would be terrible for people with a slower internet connection or limited data.

Can I write an npm run script to automate an ftp load to my server?

In VSCode I'm using ftp-simple to upload a directory of static files from a Svelte site.
I would like to automate this, presumably using npm, so that when I run npm run build it also uploads the build folder to the specified ftp.
What can I use for this? ftp-deploy seems likely, but I'm not sure how to configure package.json etc.
Any help would be appreciated.
The documentation for npm scripts explains. Briefly, though:
In package.json, find (or create) the scripts property. Find or add a build property to that. The value should be the command required to upload. That can be a script that you write (using ftp-deploy or something else) or it can be a CLI tool that is installed as a dev dependency or a regular command or set of commands available to your shell.
So you might end up with something like this (but it probably won't be this exactly):
{
"scripts": {
"build": "myAwesomeFtpDeployScript.js"
}
}

Make global npm scripts available to many subprojects

We have a monorepo with many subprojects.
root/
complex/dir/layout/subproj1
complex/dir/layout/subprojB
other/dir/subproj2
I'd like to have certain scripts available globally that were available to all the different subprojects. An example is a script we've been using to deploy AWS lambdas, like
"scripts": {
"1up:slsdeploy": "npx serverless deploy --aws-profile prod --region 'us-west-2' --description $((git branch --show-current; git rev-parse --short HEAD; id -un) | tr '\\n' ' ')"
},
Copying this and maintaining this in our 40 different lambdas isn't DRY. An answer specifically about serverless is not the main goal, but that is the immediate issue. But I would prefer more general techniques to make global scripts available to subprojects.
The most obvious answer -- just putting it in the root package.json does not appear to work (as dependencies do).
I also came across an interesting thing about the environment variables npm makes available (toward the end) at https://www.twilio.com/blog/npm-scripts that says you can reference settings in .npmrc like $npm_config_, so I though I might be able to put something in the top level .npmrc, like
MY_SPECIAL_CMD = "do something really special"
And then reference that in my individual package.json
"scripts": {
"1up:slsdeploy": "$npm_config_MY_SPECIAL_CMD"
},
which would be better, and maybe even MORE correct, since every predefined script may not be appropriate for every subproject. But apparently this only applies to the DEFINED configuration settings for .npmrc (and npm silently ignores settings it doesn't recognize, which seems like a bug). So this doesn't work.

What does scripts "npm run dev" and "npm run watch" is used for?

I'm new in vue, and a documentation says that every time I create a component I have to run npm run dev and npm run watch.
But don't know what their purpose is?
Can someone help me?
npm run dev combines all your Vue components and other JavaScript files into a browser-friendly combined file.
npm run watch does the same, but then it stays active and "watches" for updates to your .vue and .js files. If it detects a change, it'll re-build the browser-friendly file so you can just refresh the page.
Technically those will just run whatever scripts are defined in your package.json with the name dev and watch. Without seeing your package.json it's impossible to know exactly what they do.
For most project configurations those commands will compile your Vue components into raw javascript. The difference between dev and watch is the dev command will compile the code then exit while the watch command will compile the components then watch the files and recompile when one of them changes.

See webpack dev server logging

I have a vue-CLI project. Is there a simple way of viewing requests to the webpack dev server?
i.e. in the console after i've ran npm run dev and I get the message Your application is running here: http://localhost:8081 etc, I would like to see the hits to the webserver
I've added DEBUG='express:*'to my environment variables (windows) but it seems to make no difference.
Windows is funny. The standard approach is to use set VAR=val && webpack-dev-server... but that doesn't work on UNIX. I couldn't come up with a single command that would work on both a Windows and a UNIX shell.
Instead, to keep everything consistent, I'm now using the handy helper module cross-env
It's designed for exactly this purpose, and is easy to use. Just use cross-env where you'd typically use UNIX-style env, and away you go. Mine, for example, looks like:
"scripts": {
"start": "cross-env DEBUG=express:router webpack-dev-server ...."
}
This gives me portable request logging from webpack in development mode.