Before publishing my script, I have a number of scripts under the package.json to compile coffeescript, typescript and developer only commands - which make no sense once it's published.
I was wondering if there is a procedure for removing certain scripts under the package.json ? Considering that when publishing your package, it also publishes package.json.
Would this be possible to kind of remove scripts before publishing the package?
Once I publish my script, I remove a lot of the typescript and coffeescript source files (as they have been compiled), so a script I have for building no makes no sense for the published package.
Is this feasible? Or should I be thinking about another way?
"Would this be possible to kind of remove scripts before publishing the package ?"
npm does not include a built-in feature to remove scripts from package.json
.
"Is this feasible? Or should I be thinking about another way ?"
There are a couple of built-in features known as Pre and Post hooks which can be utilized to meet your requirement, albeit in a rather custom way. The pertinent hooks are prepublish
and postpublish
and are described in the documentation as follows;
prepublish: Run BEFORE the package is packed and published, as well as on local
npm install
without any arguments...postpublish: Run AFTER the package is published.
A synopsis of the solution is:
Utilize a prepublish
script in your projects package.json
to invoke a custom nodejs script. This nodejs script performs the following:
package.json
data and caches it.scripts
section of package.json
.package.json
.Utilize a postpublish
script in your projects package.json
to invoke another custom nodejs script. This secondary nodejs script performs the following:
package.json
back to it's original state.The following nodejs script will carry out the tasks mentioned in point one above. Let's name it cleanse-pkg.js
.
cleanse-pkg.js
const fs = require('fs');
const path = require('path');
// Define absolute paths for original pkg and temporary pkg.
const ORIG_PKG_PATH = path.resolve(__dirname, '../package.json');
const CACHED_PKG_PATH = path.resolve(__dirname, '../../cached-package.json');
// Obtain original `package.json` contents.
const pkgData = require(ORIG_PKG_PATH);
if (process.argv.length <= 2) {
throw new Error('Missing npm scripts key/name argument(s)');
}
// Get list of arguments passed to script.
const scriptsToRemove = process.argv[2].split(',');
const devDepsToRemove = process.argv[3] ? process.argv[3].split(',') : [];
// Write/cache the original `package.json` data to `cached-package.json` file.
fs.writeFile(CACHED_PKG_PATH, JSON.stringify(pkgData), function (err) {
if (err) throw err;
});
// Remove the specified named scripts from the scripts section.
scriptsToRemove.forEach(function (scriptName) {
delete pkgData.scripts[scriptName];
});
// Remove the specified named pkgs from the devDependencies section.
devDepsToRemove.forEach(function (pkgName) {
delete pkgData.devDependencies[pkgName];
});
// Overwrite original `package.json` with new data (i.e. minus the specific data).
fs.writeFile(ORIG_PKG_PATH, JSON.stringify(pkgData, null, 2), function (err) {
if (err) throw err;
});
The following secondary nodejs script will carry out the task mentioned in point two above. Let's name this one restore-pkg.js
.
restore-pkg.js
const fs = require('fs');
const path = require('path');
// Define absolute paths for original pkg and temporary pkg.
const ORIG_PKG_PATH = path.resolve(__dirname, '../package.json');
const CACHED_PKG_PATH = path.resolve(__dirname, '../../cached-package.json');
// Obtain original/cached contents from `cached-package.json`.
const pkgData = JSON.stringify(require(CACHED_PKG_PATH), null, 2) + '\n';
// Write data from `cached-package.json` back to original `package.json`.
fs.writeFile(ORIG_PKG_PATH, pkgData, function (err) {
if (err) throw err;
});
// Delete the temporary `cached-package.json` file.
fs.unlink(CACHED_PKG_PATH, function (err) {
if (err) throw err;
});
The prepublish
and postpublish
scripts are defined in the projects package.json
as follows:
Contrived original package.json
{
...
"scripts": {
"keep": ... ,
"a": ... ,
"b": ... ,
"prepublish": "node .scripts/cleanse-pkg \"a,b,prepublish,postpublish\"",
"postpublish": "node .scripts/restore-pkg"
},
...
}
Note the \"a,b,prepublish,postpublish\"
part in the prepublish
script. This defines the argument to pass to cleanse-pkg.js
(i.e. it lists the names of each script to be removed before publishing). Each named script to be removed must be; provided as a single string, be separated with commas, and must not include spaces.
Both cleanse-pkg.js
and restore-pkg.js
reside in a hidden folder named .scripts
, which itself resides at the top level of the projects directory, (i.e. at the same level as the projects package.json
). Both nodejs scripts can be relocated as preferred, and the paths to them redefined as necessary in the respective npm-script .
Given the contrived package.json
above, the actual package.json
contents in the resultant published tarball will be as follows:
Resultant/published package.json
{
...
"scripts": {
"keep": ...
},
...
}
Maybe there are packages listed in the devDependencies
section of your projects package.json
that you also want removed in the published package.json
.
(Note: Any packages listed in the devDependencies section are not downloaded when the user installs via the npm-registry though).
However, perhaps you'd like to remove them anyway. If that's a requirement, then cleanse-pkg.js
also accepts an optional second argument. This argument is analogous to the first argument, whereby each named package to be removed from the devDependencies
section must be; provided as a single string, be separated with commas, and must not include spaces.
Let's assume the original package.json
is as follows this time:
Contrived original package.json
{
...
"scripts": {
"keep": ... ,
"a": ... ,
"b": ... ,
"prepublish": "node .scripts/cleanse-pkg \"a,b,prepublish,postpublish\" \"x,z\"",
"postpublish": "node .scripts/restore-pkg"
},
"devDependencies": {
"x": "^1.0.2",
"y": "^0.8.1",
"z": "^0.8.1"
},
...
}
\"x,z\"
argument added to the prepublish
script to specify which packages to omit from the devDependecies
section.This time, given the contrived package.json
above, the actual package.json
contents in the resultant published tarball will be as follows:
Resultant/published package.json
{
...
"scripts": {
"keep": ...
},
"devDependencies": {
"y": "^0.8.1"
},
...
}
This solution assumes npm publish will be run utlizing one of the following methods:
npm publish
.package.json
. E.g. npm publish path/to/package.json
.This will not work by providing a url or file path to a gzipped tar archive containing a single folder with a package.json
file inside.
To prevent both utility nodejs scripts, (cleanse-pkg.js
and restore-pkg.js
), from being published they should be added to your projects .npmignore file. Given the location of both these files explained above you can add a .scripts
entry in .npmignore
.
Both utility nodejs scripts, cleanse-pkg.js
and restore-pkg.js
, define:
package.json
file.cached-package.json
file should be written. Currently this is saved one-level-up/outside from the project directory to avoid it being published).If you choose to store cleanse-pkg.js
and restore-pkg.js
to a different location than the one described above, the paths in following code snippet will need to redefined as necessary in both files.
const ORIG_PKG_PATH = path.resolve(__dirname, '../package.json');
const CACHED_PKG_PATH = path.resolve(__dirname, '../../cached-package.json');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With