I am publishing a library to NPM.
When I build the library, the resulting artifact is placed in the dist
folder located in the root of my project as index.js
.
When users install from NPM I would like index.js
to be present in the root of the folder created in their node_modules
folder. Presently, it remains in a directory named dist
.
How can I do this?
My packages.json:
{
"name": "my-package",
"version": "0.0.9",
"files": ["dist/*"],
"main": "index.min.js",
"private": false,
"dependencies": {},
"devDependencies": {},
"repository": "git@github.com:username/my-package.git"
}
I had exactly the same problem.
I solved it not by copying the files up, but by copying the files I needed down into the ./dist/
folder and then doing an npm publish
from there; NPM then treats that folder as a complete package and everything works very nicely. The only files I needed to copy from the root folder were:
Because we're going to copy these files down into the ./dist/
folder before we do the publish, we do NOT want the package.json
file to reference ./dist/
. So remove the package.json
's files
entry completely, because we don't need to tell it which files we'll take - we're going to take everything in the ./dist/
folder. I'm using TypeScript so I also have a typings
entry, and again no reference to ./dist/
.
{
"name": "my-package",
"version": "0.0.9",
"main": "index.min.js",
"typings": "index.d.ts",
"private": false,
"dependencies": {},
"devDependencies": {},
"repository": "git@github.com:username/my-package.git"
}
Now for the publish step. I built a gulp task that will perform the publish for me, making it nice and automated (except for incrementing the package version #).
From gulp I'll use Node's spawn() to kick-off the npm process. However, because I'm actually working on Windows I used "cross-spawn" rather than the normal built-in Node.js spawn (which I learned the hard way didn't work when I had spaces in my path!).
Here's my gulp file, with the TypeScript bits removed:
var gulp = require('gulp');
var del = require('del');
var spawn = require('cross-spawn'); // WAS: require('child_process').spawn;
var config = {
src: { tsFiles: './src/**/*.ts' },
out: { path: './dist/' }
}
gulp.task('clean', () => {
return del('dist/*');
});
gulp.task('build', ['clean'], () => {
....
});
gulp.task('publish', ['build'], (done) => {
// Copy the files we'll need to publish
// We just use built-in gulp commands to do the copy
gulp.src(['package.json', 'README.md']).pipe(gulp.dest(config.out.path));
// We'll start the npm process in the dist directory
var outPath = config.out.path.replace(/(\.)|(\/)/gm,'');
var distDir = __dirname + '\\' + outPath + '\\';
console.log("dist directory = " + distDir);
// Start the npm process
spawn('npm', ['publish'], { stdio:'inherit', cwd:distDir } )
.on('close', done)
.on('error', function(error) {
console.error(' Underlying spawn error: ' + error);
throw error;
});
});
Notice when we call spawn() we pass in a 3rd argument which is the options. The main entry here is the cwd:distDir
, which tells spawn to run the npm process from the ./dist/ directory. Because using spawn can cause problems I've hooked into the spawn error handling. As I was troubleshooting my use of spawn()
I found the following StackOverflow article very helpful.
This worked like a charm; my published package has all the files in the root directory and the ./dist/
folder is not published.