sindresorhus / trash

Move files and directories to the trash
MIT License
2.57k stars 78 forks source link

TypeError [ERR_INVALID_ARG_TYPE] on Windows using Next.js #129

Open kjetilhartveit opened 1 month ago

kjetilhartveit commented 1 month ago

trash() throws the following error when using Next.js on Windows: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of URL. Received an instance of URL at async deleteAction (./app/actions/delete.ts:14:5)

Reproducable example at https://github.com/kjetilhartveit/nextjs-sindresorhus-trash.

I've determined the issue is linked to what import.meta.url is returning in Next.js. In Next.js it looks like this "/_next/static/media/windows-trash.2b7fe177.exe". In the trash library the Windows trash binary is imported like this const binary = new URL('windows-trash.exe', import.meta.url);. Even though an URL is created, it fails later in a call to fileURLToPath() because it is missing a protocol (e.g. file:). fileURLToPath() validates the path using a isURL(path) there you can see it expects a protocol to be set.

My temporary fix in my side-project has been to download the recycle-bin binary directly and then copied the logic from https://github.com/sindresorhus/trash/blob/main/lib/windows.js and https://github.com/sindresorhus/trash/blob/main/lib/chunked-exec.js except that the binary was "imported" like this const pathToRecycleBinary = dirname(dirname(import.meta.url)) + "/binary/recycle-bin.exe";

Ala this:

"use server";

import { promisify } from "node:util";
import { execFile } from "node:child_process";
import { fileURLToPath } from "node:url";
import chunkify from "@sindresorhus/chunkify";
import { dirname } from "node:path";

const pathToRecycleBinary =
  dirname(dirname(import.meta.url)) + "/binary/recycle-bin.exe";
const pExecFile = promisify(execFile);

export async function deleteFile(path: string) {
  for (const chunk of chunkify([path], 200)) {
    const urlToBinary = fileURLToPath(pathToRecycleBinary);
    await pExecFile(urlToBinary, chunk);
  }
}

I don't know if this is the best solution (importing the binary differently) to the problem though.

Note: not sure if this only affects Windows users

ChaiyoKung commented 3 weeks ago

This is my workaround

  1. Downgrade trash to version 7.2.0 to use commonjs (If you install version >= 8)
    pnpm add trash@^7.2.0
  2. Modified webpack config in next.config.js to included executable file in .next (here is example)
    
    const CopyWebpackPlugin = require("copy-webpack-plugin");
    const { resolve } = require("node:path");

const nextConfig = { webpack: (config, context) => { const { isServer, dev } = context;

if (isServer) {
  const chunkDirName = dev ? "vendor-chunks" : "chunks";
  const chunkDirPath = resolve(__dirname, ".next/server", chunkDirName, "[name][ext]");
  config.plugins.push(
    new CopyWebpackPlugin({
      patterns: [
        { from: resolve(__dirname, "../../node_modules/trash/lib/windows-trash.exe"), to: chunkDirPath },
        { from: resolve(__dirname, "../../node_modules/trash/lib/macos-trash"), to: chunkDirPath },
      ],
    })
  );
}

return config;

}, };

module.exports = nextConfig;



Can view full version of code in my [repo](https://github.com/ChaiyoKung/dup-detector/pull/21/files#diff-a5de0fa0d80f14a44e9bdf2ed5d0cbb3a7bd5fdcacfbc1d03b5dcb57fc4943c1)

Information:
- Next.js `v14.2.3`
- trash `v7.2.0`
- copy-webpack-plugin `v12.0.2`