使用Webpack/Parcel打包basic-ftp模块在浏览器报错求助
问题:basic-ftp在浏览器构建环境中报错,Node环境正常
问题描述
使用Webpack 5或Parcel构建包含basic-ftp@5.0.4的JS文件,在Node.js命令行运行正常,但在Windows 11浏览器中报错,错误指向util.promisify参数类型错误。
浏览器错误信息
Uncaught TypeError: The "original" argument must be of type Function at promisify (util.js:614:11) at 5u8Fu.c4216f9df743e6cc (Client.js:17:38) at newRequire (index.47c005a7.js:71:24) at localRequire (index.47c005a7.js:84:35) at 2uKas.b1c576accb3ceae3 (index.js:21:14) at newRequire (index.47c005a7.js:71:24) at localRequire (index.47c005a7.js:84:35) at 8Duvb.44a9388bb99fc836 (index1.js:7:16) at newRequire (index.47c005a7.js:71:24) at index.47c005a7.js:122:5
相关文件内容
src/index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"/> <title>My First Parcel App</title> <link rel="stylesheet" href="main.css" /> <script type="module" src="index1.js"></script> </head> <body> <h1>Hello, World!</h1> </body> </html>
src/index1.js
// src/index1.js // works with node index1.js console.log("Starting"); const Client = require("basic-ftp") //import * as Client from "basic-ftp" example(); async function example() { const client = new Client.Client() client.ftp.verbose = true try { await client.access({ host: "somehost", user: "username", password: "password", secure: false }) console.log(await client.list()) //await client.uploadFrom("README.md", "README_FTP.md") //await client.downloadTo("README_COPY.md", README_FTP.md") } catch(err) { console.log(err) } client.close() } console.log("Finished!");
package.json
{ "name": "parcel-demo", "version": "1.0.0", "description": "", "main": "index.js", "source": "src/index.html", "scripts": { "start": "parcel", "build": "parcel build" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "buffer": "^6.0.3", "node": "^21.2.0", "parcel": "^2.10.3" }, "dependencies": { "basic-ftp": "^5.0.4" } }
依赖列表
+-- basic-ftp@5.0.4 +-- buffer@6.0.3 +-- node-bin-setup@1.1.3 extraneous +-- node@21.2.0 `-- parcel@2.10.3
构建命令
npx parcel src/index.html --open
解决方案
问题根源在于basic-ftp是Node.js专属库,依赖Node环境特有的API(如net、tls模块,以及util.promisify处理的Node原生异步方法),这些API在浏览器环境中不存在,所以构建后运行会报错。
解决步骤:
- 改用后端代理方案:浏览器本身出于安全和协议限制,不支持直接发起FTP连接,需通过Node.js后端完成FTP操作,前端调用后端接口获取结果。
- 调整项目架构:将FTP相关逻辑全部移至服务端,前端仅负责发起请求和展示数据。
示例调整(后端代理方式)
1. 新建Node服务文件(server.js)
const express = require('express'); const { Client } = require('basic-ftp'); const app = express(); const port = 3000; app.use(express.json()); app.get('/ftp/list', async (req, res) => { const client = new Client(); client.ftp.verbose = true; try { await client.access({ host: "somehost", user: "username", password: "password", secure: false }); const list = await client.list(); res.json(list); } catch (err) { res.status(500).json({ error: err.message }); } finally { client.close(); } }); app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); });
2. 前端修改index1.js
console.log("Starting"); async function example() { try { const response = await fetch('http://localhost:3000/ftp/list'); const list = await response.json(); console.log(list); } catch (err) { console.log(err); } } example(); console.log("Finished!");
3. 启动服务并运行前端
- 安装依赖:
npm install express - 启动后端:
node server.js - 启动前端:
npx parcel src/index.html --open
通过这种方式,前端通过调用后端接口间接完成FTP操作,避开浏览器环境的限制。
内容的提问来源于stack exchange,提问作者bren
相关产品推荐
相关产品推荐

