解决 vite build 在 pnpm 工程下出现 fsevents.node Unexpected character 的问题
问题现象
近期在使用 vite 开发一个 通用型插件,用于实现 基于文件系统驱动路由的 react 页面应用。包管理工具使用的是 pnpm@9.6.0,打包工具是 vite@5.3.5。
在构建的时候出现以下错误:
▷ pnpm run build
> unplugin-react-pages@0.1.0 build /unplugin-react-pages
> NODE_ENV=production vite build
vite v5.3.5 building for production...
✓ 63 modules transformed.
x Build failed in 5.00s
error during build:
[commonjs--resolver] node_modules/.pnpm/fsevents@2.3.3/node_modules/fsevents/fsevents.node (1:0): Unexpected character '�' (Note that you need plugins to import files that are not JavaScript)
file: /unplugin-react-pages/node_modules/.pnpm/fsevents@2.3.3/node_modules/fsevents/fsevents.js:1:0
1: ����@<�
��*...
^
4*
h���/System/Library/Frameworks/CoreFoundation.framework/Versions...
3: ���H��1�H���L���L���H�����L�E�L��H��1�����uH�E�H�[A^A_]��}f.�UH��AWAVSPI��H��I��H�H...
RollupError: Unexpected character '�'
at getRollupError (file:///unplugin-react-pages/node_modules/.pnpm/rollup@4.19.1/node_modules/rollup/dist/es/shared/parseAst.js:392:41)
at ParseError.initialise (file:///unplugin-react-pages/node_modules/.pnpm/rollup@4.19.1/node_modules/rollup/dist/es/shared/node-entry.js:11471:28)
at convertNode (file:///unplugin-react-pages/node_modules/.pnpm/rollup@4.19.1/node_modules/rollup/dist/es/shared/node-entry.js:13167:10)
at convertProgram (file:///unplugin-react-pages/node_modules/.pnpm/rollup@4.19.1/node_modules/rollup/dist/es/shared/node-entry.js:12511:12)
at Module.setSource (file:///unplugin-react-pages/node_modules/.pnpm/rollup@4.19.1/node_modules/rollup/dist/es/shared/node-entry.js:14332:24)
at async ModuleLoader.addModuleSource (file:///unplugin-react-pages/node_modules/.pnpm/rollup@4.19.1/node_modules/rollup/dist/es/shared/node-entry.js:18984:13)
ELIFECYCLE Command failed with exit code 1.
解决方案 1(推荐)
因为本工程是 library 类型,一般外部依赖都不需要捆绑在一起的,因此需要在 vite.config 的 rolluOptions 内配置 external 将外部依赖排除即可。通常我们使用 vite-plugin-externalize-deps 配置一下:
// vite.config.ts
import { externalizeDeps } from 'vite-plugin-externalize-deps';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
externalizeDeps({
deps: true,
devDeps: true,
peerDeps: true,
optionalDeps: true,
nodeBuiltins: true,
}),
],
});
解决方案 2
fsevents package
Native access to MacOS FSEvents in Node.js
The FSEvents API in MacOS allows applications to register for notifications of changes to a given directory tree. It is a very fast and lightweight alternative to kqueue.
This is a low-level library. For a cross-platform file watching module that uses fsevents, check out Chokidar.
fsevents 入口会引用该文件:
而 vite 在构建引用二进制文件时目前会有问题,即使加上排除也不行:
export default defineConfig({
// ...
optimizeDeps: { exclude: ["fsevents"] },
// ...
})
而 fsevents 是 chokidar 的可选依赖:
那就索性不安装该依赖试试,在 package.json 里添加:
...
"optionalDependencies": {
"fsevents": "*"
}
...
最后构建成功。
</>
</>