1

So, I have a library haste-mapper (link to Github - I would like some opinions on it). It uses gulp, babel-core and a few other npm packages to build itself so as to have valid JavaScript instead of Flow into the build/ directory. I added that as a postinstall hook script in package.json:

"postinstall": "gulp build"

It works, the script starts running but it does not meet the required dependencies in the host package. I have gulp and babel-core as devDependencies and it seems not to install them. Adding them to dependencies seems semantically wrong. I tried adding them to peerDependencies, but instead of installing what's missing, it just complains about it.

How should I go about this?

P.S. Here is the package.json

Victor
  • 13,914
  • 19
  • 78
  • 147

2 Answers2

5

If you want to use something in a postinstall hook, it needs to be a dependency.

However, you're doing it wrong. You shouldn't be transpiling your code after the install. Instead, you should transpile your code before you publish the package.

To do that, you will need to rename your script to prepublish so that it is run when you run npm publish. List gulp, babel, etc. as devDependencies. Add an .npmignore file in the root of your project, containing:

/src/

The .npmignore file works just like a .gitignore. You don't want your src/ directory included in the published package, only build/. Make sure .npmignore is committed to git. If you don't have an .npmignore, npm will use the .gitignore file. This isn't what you want, since build/ is ignored for version control, but should be included in the npm package.

When you run npm publish, npm will run your prepublish hook before bundling your package for the registry. Then when someone npm installs your package, they will get the build/ folder, but not src/. Just what you want!

RyanZim
  • 6,609
  • 1
  • 27
  • 43
  • I always thought NPM grabs the code of the package straight from the git repository... – Victor Nov 21 '16 at 18:22
  • 1
    Nope, you push to npm separately. – Ryan Wheale Nov 21 '16 at 18:23
  • "However, you're doing it wrong. ", What if the package is a private git repo. – towry May 21 '20 at 09:55
  • @towry It's preferable to publish it as a private npm module. If you don't want to do that, you're basically forced to check your built code into git. You can either update the built code on every commit, or only for tagged releases. – RyanZim May 21 '20 at 12:15
3

I started to leave a comment on RyanZim's answer because his technique is correct. However, I wanted to give a slightly different approach. Our company maintains a lot of open source projects and this is how we would advise you.

  • Keep developing your project like you normally would. Your .gitignore file should be ignoring your dist directory (/build in your case).
  • When you are ready to deploy, you want to build your code, bump your version number inside package.json, tag the changes, and push the built code to both github and npm.

The main idea is that we want to keep a copy of our built code in github along with a "tag" for that version. This allows us to see exactly what was pushed to npm for any particular version. The built code is not part of the master branch but exists only under a tag (which is sort of like a branch). When a user reports a bug and he's using version x.x.x, you can checkout that exact version and start debugging. When you fix the bug, you release a new "patch" and your user will get the changes the next time he runs npm install or npm update.

We have created a set of npm scripts to do most of this for us. Here is what we use (this goes in your package.json):

"scripts": {
    "build": "node build.js",
    "preversion": "npm run build",
    "version": "git commit -am \"Update dist for release\" && git checkout -b release && git add -f dist/",
    "postversion": "git push --tags && git checkout master && git branch -D release && git push",
    "release:pre": "npm version prerelease && npm publish",
    "release:patch": "npm version patch && npm publish",
    "release:minor": "npm version minor && npm publish",
    "release:major": "npm version major && npm publish"
}

I know that may look confusing so let me explain. Whenever we are ready to release new code, we run one of the release: commands. For example, when we run npm run release:minor, here is the list of commands which are run in order. I have annotated it so you can see what happens:

node build.js             ## run the build code - you will want to run gulp instead
npm version minor         ## bumps the version number in package.json and creates a new git tag
git commit -am "Update dist for release"    ## commit the package.json change to git (with new version number) - we will push it at the end
git checkout -b release   ## create a temporary "release" branch
git add -f dist/          ## force add our dist/ directory - you will want to add your build/ directory instead
npm publish               ## push the code to npm
git push --tags           ## push the built code and tags to github
git checkout master       ## go back to the master branch
git branch -D release     ## delete the temporary "release" branch
git push                  ## push the updated package.json to github

If you have any questions, please ask. You might want to do things in a slightly different order as your situation is a little different. Please feel free to ask questions. This code works really well on dozens of projects - we release new code multiple times a day.

Ryan Wheale
  • 26,022
  • 8
  • 76
  • 96
  • Tip: let your CI do the releasing, that way the developer has to do less and when the developer has to do less, the developer makes less mistakes. – Stephan Bijzitter Nov 21 '16 at 19:46
  • Ha, I didn't even want to touch CI as this post is overwhelming enough. Thanks though. Also, we do a lot of iterations and use CI only for running tests in multiple environments. When everything passes and we are ready, we release by hand which ensures that our tags are in sync with npm and nothing goes out too soon. We handle client projects differently. To each his own though. – Ryan Wheale Nov 21 '16 at 19:53