Skip to content

webpack5的持久化缓存和cnpm的安装包名之间有冲突,导致webpack5假死,无法生成缓存文件 #335

Open
@zhangrenyang

Description

@zhangrenyang

最小复现仓库地址
webpack5-cache-debug

webpack版本如下

  "devDependencies": {
    "webpack": "^5.10.3",
    "webpack-cli": "^4.2.0"
  },

webpack配置文件如下

webpack.config.js

module.exports = {
  cache: {
        type: 'filesystem' //写入缓存到硬盘
  },
   snapshot: {
        managedPaths: [path.resolve(__dirname, 'node_modules')],//配置包管理器管理的路径
    }
}

经过认真排查确定问题出在这里
https://github.com/webpack/webpack/blob/911ec1aa67011e25aa1449610f5b0b557edd5459/lib/FileSystemInfo.js#L1571

https://github.com/webpack/webpack/blob/911ec1aa67011e25aa1449610f5b0b557edd5459/lib/FileSystemInfo.js#L693

  • 就是wepback5约定包名必须以@开头。如果不是以@开头的话就直接返回null了,导致无法webpack5无法获取管理资源,导致会计算包下所有的文件和文件夹的hash值和时间戳,导致超时假死

  • 正常的包名是 C:/node_modules/@babel_helper-module-import

  • cnpm安装的包名为 C:/node_modules/_@babel_helper-module-import

测试代码如下

const getManagedItem = (managedPath, path) => {
    debugger
	let i = managedPath.length;
	let slashes = 1;
	let startingPosition = true;
	loop: while (i < path.length) {
		switch (path.charCodeAt(i)) {
			case 47: // slash
			case 92: // backslash
				if (--slashes === 0) break loop;
				startingPosition = true;
				break;
			case 46: // .
				// hidden files are disallowed as managed items
				// it's probably .yarn-integrity or .cache
				if (startingPosition) return null;
				break;
			case 64: // @
+				if (!startingPosition) return null;
				slashes++;
				break;
			default:
				startingPosition = false;
				break;
		}
		i++;
	}
	if (i === path.length) slashes--;
	// return null when path is incomplete
	if (slashes !== 0) return null;
	// if (path.slice(i + 1, i + 13) === "node_modules")
	if (
		path.length >= i + 13 &&
		path.charCodeAt(i + 1) === 110 &&
		path.charCodeAt(i + 2) === 111 &&
		path.charCodeAt(i + 3) === 100 &&
		path.charCodeAt(i + 4) === 101 &&
		path.charCodeAt(i + 5) === 95 &&
		path.charCodeAt(i + 6) === 109 &&
		path.charCodeAt(i + 7) === 111 &&
		path.charCodeAt(i + 8) === 100 &&
		path.charCodeAt(i + 9) === 117 &&
		path.charCodeAt(i + 10) === 108 &&
		path.charCodeAt(i + 11) === 101 &&
		path.charCodeAt(i + 12) === 115
	) {
		// if this is the end of the path
		if (path.length === i + 13) {
			// return the node_modules directory
			// it's special
			return path;
		}
		const c = path.charCodeAt(i + 13);
		// if next symbol is slash or backslash
		if (c === 47 || c === 92) {
			// Managed subpath
			return getManagedItem(path.slice(0, i + 14), path);
		}
	}
	return path.slice(0, i);
};
console.log(getManagedItem('C:/node_modules/','C:/node_modules/_@babel_helper-module-import'));
打印null

Activity

changed the title [-]webpack5和持久化缓存和cnpm的安装包名之间有冲突,导致webpack5假死,无法生成缓存文件[/-] [+]webpack5的持久化缓存和cnpm的安装包名之间有冲突,导致webpack5假死,无法生成缓存文件[/+] on Dec 17, 2020
fengmk2

fengmk2 commented on Dec 19, 2020

@fengmk2
Member

我今天会跟进看看。

fengmk2

fengmk2 commented on Dec 19, 2020

@fengmk2
Member

我简单看了一下,主要是 webpack 读取了绝对路径,这个比较难搞。cnpm 使用了软连接来提速。可能还需要看看 snapshot 的 managedPaths 配置。

zhangrenyang

zhangrenyang commented on Dec 19, 2020

@zhangrenyang
Author

@fengmk2 是的,比较棘手。
主要原因在于webpack写死了这个规则,而这个规则是符合标准的,并非webpack的BUG或者问题,所以webpack几乎不可能修改它的规则。
而cnpm这种模式也不好改,要去迎合webpack的规则改动也会比较大。
关于snapshot的配置我都仔细研究过了,个人认为跟managedPaths配置关系不大了,主要问题就在这个读取规则上,如何兼容。

lceric

lceric commented on Jun 23, 2021

@lceric

可以试着本地patch一下,调整一下这个规则

https://www.npmjs.com/package/patch-package

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @fengmk2@zhangrenyang@lceric

        Issue actions

          webpack5的持久化缓存和cnpm的安装包名之间有冲突,导致webpack5假死,无法生成缓存文件 · Issue #335 · cnpm/cnpm