Skip to content

解决VMware共享文件夹下安装node_modules报错的问题 #9

Description

@guilixie

背景

因为公司提供的办公电脑是Windows系统,本人之前一直使用的Ubuntu系统开发的,所以就比较难受了。于是我有了用VMware虚拟机安装一个Ubuntu桌面版的想法,经过一番折腾以后,就可以愉快的写代码了~~~

发现问题

在我使用yarn安装项目依赖的时候,总是会出现如下的错误,真是让人苦恼。不如换成npm install 试试,结果如出一辙,报错信息如下所示:

guili@guili-virtual-machine:/mnt/hgfs/UbuntuShare/workspace/my-app$ yarn
yarn install v1.22.10
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
error An unexpected error occurred: "ENOTSUP: operation not supported on socket, symlink '../../../../@babel/parser/bin/babel-parser.js' -> '/mnt/hgfs/UbuntuShare/workspace/my-app/node_modules/@vue/compiler-core/node_modules/.bin/parser'".
info If you think this is a bug, please open a bug report with the information provided in "/mnt/hgfs/UbuntuShare/workspace/my-app/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.

于是,我拍案而起,这也太坑了吧。

分析问题

查阅了资料,了解到vmhgfs(应用于VMware共享文件夹的Linux端vfs)不支持symlink(或者可能是不支持Linux和Windows下的符号链接格式互相转换)。原理是安装基于nodejs的项目时,如果安装的模块的package.json 中定义了bin 字段,那么yarn或者npm就会自动创建一个符号链接到node_modules/.bin文件夹下。

因为VMware的“共享文件夹”是不支持自动符号链接转换的,所以这个功能在VMware的“共享文件夹”下是没法正常工作的,就会导致上述的报错信息的出现。

解决方案

一、bin-links

npm提供了bin-links配置项,可以告诉 npm 为包可执行文件创建符号链接(或 Windows 上的 .cmd 垫片)。 设置为 false 使其不这样做。这可以用来解决一些文件系统不支持符号链接的事实,即使在表面上是 Unix 系统上。

npm

你可以直接在~/.npmrc写入,

bin-links=false

或者直接命令设置全局的配置如下:

npm config set bin-links=false

另外,还可以直接使用

npm install --no-bin-links

yarn

你可以直接在~/.yarnrc写入,

"--*.no-bin-links" true
or
bin-links false

或者直接命令设置全局的配置如下:

yarn config set bin-links false

另外,还可以直接使用

yarn --no-bin-links

二、nodejs脚本

使用上述的方法,只是安装模块的时候不再报错,但是当执行scripts字段下的run命令时,还是会有报错,说找不到某某模块。比如有一个webpack打包的项目,然后已经使用--no-bin-links安装好所以依赖。对于webpack,找到其package.json,发现配置有bin字段:

"bin": {
    "webpack": "./bin/webpack.js"
}

可知此模块有一个cli入口,入口名和包一致,为webpack,对应执行模块目录内的./bin/webpack.js。

既然无法用符号链接来指向这个文件,我们可以曲线救国,使用脚本完成这个事。首先需要在node_modules目录下创建.bin文件夹,然后创建文件webpack.js,写入内容如下:

#! /bin/bash
node './node_modules/webpack/bin/webpack.js' $*

最后的$*是为了将所有命令行参数完整的传给对应脚本。

然后就需要使用chmod命令给已经写好的脚本执行权限。

chmod +x ./node_modules/.bin/webpack

然后运行项目就可以正常使用webpack命令了。

完整的代码如下:

const fs = require('fs')
const path = require('path')

// get package list from package.json
const packageList = require('./package.json').devDependencies

// get all package name from packageList
const packageNameList = Object.keys(packageList)

const CLIList = []

const convertPath = (packageName, binaryPath) => path.resolve(`./node_modules/${packageName}/`, binaryPath)

for (let packageName of packageNameList) {
	// load package config
	const packageConf = require(`./node_modules/${packageName}/package.json`)
	if ('bin' in packageConf) {
		if (typeof packageConf.bin !== 'string') {
			for (let cmd of Object.keys(packageConf.bin)) {
				CLIList.push([cmd, convertPath(packageName, packageConf.bin[cmd])])
			}
		} else {
			CLIList.push([packageName, convertPath(packageName, packageConf.bin), true])
		}
	}
}

if (!fs.existsSync('./node_modules/.bin')) {
	fs.mkdir('./node_modules/.bin',()=>{})
} else {
	throw new Error('directory .bin exists already')
}

// make script
for (const item of CLIList) {
	const [filename, binPath, _] = item
	const script = `
        #!/bin/bash

        node "${binPath}" $*
        `
	fs.writeFileSync(`./node_modules/.bin/${filename}`, script)
	fs.chmodSync(`./node_modules/.bin/${filename}`, 777)
}

console.log(CLIList);

终于圆满解决

然后将脚本放到项目的根目录,在安装完node_modules后,运行之前,执行下这个脚本:node ./command_patch.js。

于是乎,困扰了我半天,让我加班的问题终于被我找到原因和圆满解决了~~

当然最直截了当的方法就是不用虚拟机的共享文件夹,直接在虚拟机的其它文件夹下工作。当然也就不会遇到这个问题,也不会折腾这么久了。

参考资料

  1. npm Docs - config #bin-links
  2. yarn config
  3. .yarnrc
  4. [nodejs] 解决由于VMWare共享文件夹功能bug导致的yarn(或npm)无法正常使用的问题
  5. 有关yarn/npm关闭符号链接创建后引起的一个bug的讨论

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    VMwareVMwarebugSomething isn't workingcliclinodenode

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions