Reputation: 5
Is there a way to copy the files includes in package.json
(in the File
field) to a folder to package them together with npm publish
?
My repo:
.
├── package.json
└── folder0
├── file0
└── folder1
└── file1
My package.json:
{
"name": "example",
"version": "0.2.0",
"files": [
"folder0/file0",
"folder0/folder1/file1"
],
"author": "cruiz"
}
Desired output:
I want in my package:
.
├── package.json
└── build
├── file0
└── file1
Thank you very much for the reply. I'm trying to use npm to package VHDL code, so I'm really noob :(
Is it possible to put the files to be packaged in a field of package.json and read them from the script?
{
"name": "example",
"version": "0.2.0",
"customField": [
"folder0/file0",
"folder0/folder1/file1"
],
"scripts": {
"prepublishOnly": "mkdirp build && copyfiles -f [..read CustomField...] build"
},
"author": "cruiz"
}
Upvotes: 0
Views: 4339
Reputation: 25002
Edit based on the OP's edit.
Is it possible to put the files to be packaged in a field of
package.json
and read them from the script.
Yes that's possible, however you will need to utilize a custom node script to do that. There's no existing packages available to achieve this that I am aware of.
Solution:
Firstly, cd
to your project directory and uninstall the packages I mentioned in by original answer as we wont be using them. You can do this by running the following command:
npm un -D mkdirp copyfile
Install shelljs using the following command:
npm i -D shelljs
Note: shelljs
will now be utlized instead of mkdirp
and copyfile
to create the directory then copy the files listed in package.json
.
Next create a node script with the following contents. Lets name the file copy-files.js
and save it to a hidden directory named .scripts
at the top level of your project directory. I.e.
Directory structure
project
├── .scripts
│ └── copy-files.js
├── node_modules
│ └── ...
├── package.json
├── folder0
│ ├── file0.js
│ └── folder1
│ └── file1.js
└── ...
Contents of copy-files.js
const shell = require('shelljs');
const pkg = require('../package.json');
// The path to the directory to copy the file(s) to.
const DEST_DIR = './build';
// NOTE: `customField` below should be replaced with the
// actual key name in the final `package.json`.
const srcFilePaths = pkg.customField;
// Create a new destination directory and intermediate
// directories if necessary.
if (!shell.test('-d', DEST_DIR)) {
shell.mkdir('-p', DEST_DIR);
}
// Recursively copy each file listed in the `customField` Array.
// Logs and error if the file listed cannot be found.
srcFilePaths.forEach(function (srcPath) {
if (!shell.test('-e', srcPath)) {
shell.echo('Error: Cannot find file listed in package.json: %s', srcPath);
process.exit(1);
}
shell.cp(srcPath, DEST_DIR);
});
Note: The customField
part in const srcFilePaths = pkg.customField;
, (on line 9 of copy-files.js
above), will need to be replaced with the actual real key name you decide to use in the final package.json
.
Finally, update your prepublishOnly
script to invoke the custom node script (i.e. copy-file.js
) as shown in the following excerpt of package.json
:
{
...
"customField": [
"folder0/file0.js",
"folder0/folder1/file1.js"
],
"scripts": {
"prepublishOnly": "node .scripts/copy-files",
},
...
}
This can be achieved by utilizing a custom npm-script in your package.json
file. Using a pre
script will also suit your requriement as you mentioned:
package them together with
npm publish
pre
and post
hooks with npm scripts:All npm scripts support what are referred to as pre
and post
hooks. Any pre
script will run before its respective script (or command), and any post
script will run after its respective script (or command).
To better understand this feature let's say our package.json
contains the contrived scripts shown in the following excerpt:
...
"scripts": {
"prefoo": "...",
"foo": "...",
"postfoo": "..."
},
...
As you can see:
foo
which has a corresponding script with the pre
prefix, i.e. prefoo
.foo
script also has another corresponding script, however this one is prefixed with post
, i.e. postfoo
.Specifying scripts in this way will result in the following whenever you invoke the foo
script via your CLI by running npm run foo
:
prefoo
script will automatically run before the foo
script is executed.postfoo
will automatically run after foo
completes.Further information regarding pre
and post
hooks can be found here
pre
script should I use?There are a couple of built-in pre
scripts that are likely to suit your requirement; those being prepublish
or prepublishOnly
. The npm docs provides the following description for these hooks:
prepublish: Run BEFORE the package is packed and published, as well as on local
npm install
without any arguments. (See below)
prepublishOnly: Run BEFORE the package is prepared and packed, ONLY on
npm publish
...
Note: The following solution uses the prepublishOnly
as I'm quite sure you don't want this script to run when a user runs npm install
. However, you'll need to decide whether to use this or swap it for prepublish
. Refer to the docs for the finer details of each pre
hook.
For a solution that works cross platforms you'll need to firstly cd
to your project directory and install a couple of additional npm packages.
In the scripts
section of your package.json
file add the following:
...
"scripts": {
"prepublishOnly": "mkdirp build && copyfiles -f folder0/file0.js folder0/folder1/file1.js build"
},
...
Now when you run; npm run publish
, the prepublishOnly
script will automatically run, (i.e. copy the files to meet your desired directory structure), before your package is prepared and packed for publishing.
You can of course run; npm run prepublishOnly
, if you'd like to test the results of the script before running: npm run publish
.
Upvotes: 2
Reputation: 133018
What you basically want is a build step. You could do all those things in a prepublish
script, e.g.:
package.json
{
"scripts": {
"prepublish": "mkdir -p build && cp folder0/file0 folder0/folder1/file1 build"
}
}
But you should change your files
as well, unless you really want both structures, in build
and folder0/*
.
Upvotes: 0