In my index.mjs file I have a function that concatenates and minifies JS utility files. I have it set up like this:
import fs from "fs";
import { minify } from "terser";
function concatenateAndMinifyJsFiles() {
const jsDir = "./js/";
const mainJsFile = "./js/main.min.js";
// Concatenate and minify .js files
fs.readdir(jsDir, { withFileTypes: true }, (err, files) => {
if (err) {
console.error(`Error reading directory ${jsDir}: ${err}`);
return;
}
const jsFiles = files.filter((file) => file.isFile() && file.name.endsWith(".js"));
if (jsFiles.length === 0) {
console.log(`No .js files found in ${jsDir}`);
return;
}
const concatenatedJs = jsFiles.map((file) => fs.readFileSync(`${jsDir}${file.name}`, "utf8")).join("\n");
const minifiedJs = minify(concatenatedJs).code;
fs.writeFile(mainJsFile, minifiedJs, (err) => {
if (err) {
console.error(`Error writing file ${mainJsFile}: ${err}`);
} else {
console.log(`File ${mainJsFile} has been created`);
}
});
});
}
I'm getting the following TypeError message:
node:internal/fs/utils:885
throw new ERR_INVALID_ARG_TYPE(
^
TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined
After commenting out each section at a time, it appears that the section that's using the writeFile
command:
fs.writeFile(mainJsFile, minifiedJs, (err) => {
if (err) {
console.error(`Error writing file ${mainJsFile}: ${err}`);
} else {
console.log(`File ${mainJsFile} has been created`);
}
});
The mainJsFile
value is a string. The minifiedJs
value from the Terser minify function is also a string (from the concatenatedJs
variable).
I'm using Node version 16.15.1. I can't see anything in my code that looks out of place in the Node docs. Any thoughts about why this error is getting thrown?
The error you are seeing from the fs module is correct. The value you are passing for the data argument is not one of the allowed types.
According to the documentation for Terser at https://www.npmjs.com/package/terser the minify function is asynchronous and therefore you must add await
before your call to it. The writeFile
call is complaining because the data type is actually undefined
, not string
. This is because you are trying to access the code
property of a Promise, which does not exist (and therefore JavaScript evaluates this as undefined).
Try using the following:
const result = await minify(concatenatedJs);
const minifiedJs = result.code;
Note how I split this into two variables (mainly for clarity) because you cannot access the code
property until the result has been awaited.
Edit:
As mentioned by @jfriend00 in the replies to the answer, you will need to also make sure you mark the function containing that await
keyword as async
. In your case, you'd need to mark your callback function for fs.readdir
as async. If you do not do this, you'll get an error as you cannot await other async functions in a non-async function.
fs.readdir(jsDir, { withFileTypes: true }, async (err, files) => {
// your code here
});