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/[email protected] 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.
CodePudding user response:
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.