ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Cypress 默认 webpack 预处理器与 Yarn 4 PnP 依赖解析:yarn-v4.15.0-pnp-dep-resolution 系统测试剖析

Cypress 默认 webpack 预处理器与 Yarn 4 PnP 依赖解析:yarn-v4.15.0-pnp-dep-resolution 系统测试剖析 Cypress 默认 webpack 预处理器与 Yarn 4 PnP 依赖解析yarn-v4.15.0-pnp-dep-resolution 系统测试剖析【免费下载链接】cypressFast, easy and reliable testing for anything that runs in a browser.项目地址: https://gitcode.com/GitHub_Trending/cy/cypress本指南以 Cypress 仓库内system-tests/projects/yarn-v4.15.0-pnp-dep-resolution测试夹具为中心说明当测试项目使用 Yarn 4BerryPlugnPlayPnP安装模式、依赖既不落地为node_modules目录、又需要被 Cypress 默认 webpack 预处理器打包时Cypress 如何完成支持文件的转译与依赖解析。读完本文你将理解为什么这类场景必须以二进制系统测试的方式运行、默认预处理器cypress/webpack-batteries-included-preprocessor为此做了哪些针对性设计以及如何在自己项目中复现与验证这一能力。一、这个夹具项目到底在测试什么README 的第一句话就点明了主题What are we testing?我们在测试什么。它测试的并非某个业务断言而是 Cypress 默认预处理器在一类特殊安装布局下的解析行为项目的 support 文件引用了cypress-axe而cypress-axe又依赖axe-core这两个包均由 Yarn PnP 安装不存在于node_modules中它们却要被 Cypress 通过 webpack 预处理打包——执行预处理的 webpack 及其工具链位于二进制内部的packages/server/node_modules/cypress/webpack-batteries-included-preprocessor即发布版中随 Cypress server 打包的 npm/webpack-batteries-included-preprocessor该目录相对 monorepo 根目录而言因此测试的实质是验证两条解析路径能够同时成立构建期依赖webpack 这个打包二进制需要从 Cypress 二进制内部解析它自己的构建依赖loader、babel 插件、乃至对process等内置对象的垫片用户源码依赖support/spec 文件中import cypress-axe这类依赖则必须从PnP 缓存zip 归档缓存中解析出来而不是从并不存在的node_modules中解析。README 还给出了本夹具存在的第二个理由由于依赖无法像普通 system tests 那样用 Yarn v1 常规安装因此它必须被当作**二进制系统测试binary system test**来运行对应的 CI 任务名为yarn-pnp-preprocessor-system-testREADME 原文指向./circleci/workflows.yml该 workflow 定义于仓库的 CI 配置中在当前快照的system-tests树内没有其源码仅能依据文档描述确认其存在。二、夹具项目的解剖一份极简的 Yarn 4 PnP 工程先看该夹具的完整目录结构system-tests/projects/yarn-v4.15.0-pnp-dep-resolution/ ├── cypress/ │ ├── e2e/ │ │ └── spec.cy.js │ └── support/ │ └── e2e.js ├── README.md ├── cypress.config.js ├── package.json └── yarn.lock注意目录中没有node_modules、也没有提交.pnp.cjs这与 Yarn 4 PnP 模式下依赖以 zip 形式存放在全局缓存、由运行时生成 PnP 状态文件的机制是一致的。1. package.json通过packageManager锁定 Yarn 4.15.0package.json 是理解整个夹具的关键{ name: yarn-v4.15.0-pnp-dep-resolution, version: 0.0.0-test, devDependencies: { axe-core: ^4.10.3, cypress-axe: ^1.6.0 }, packageManager: yarn4.15.0 }三个值得注意的点devDependencies刻意选择了能构成一条真实依赖链的最小集合cypress-axe是 support 文件直接引用的入口包axe-core是它传递依赖的底层库。这条链被完整地装入 PnP 缓存专门用来检验多层 PnP 依赖都能被 webpack 解析。packageManager: yarn4.15.0触发 corepackYarn 4 并不依赖仓库根目录的 Yarn v1而是通过 corepack 按packageManager字段激活对应版本这正是它无法走常规安装通道的原因之一。该工程没有配置任何自定义 webpack也没有在 cypress.config.js 中注册file:preprocessor事件因此实际生效的必然是 Cypress 内置的默认预处理器——这是让测试结果有说服力的前提。2. yarn.lockYarn 4 的 Berry 格式锁文件yarn.lock 采用的是 Yarn Berry 特有的 lockfile v10 格式这与 Yarn v1 的格式有本质区别__metadata: version: 10 cacheKey: 10c0 axe-corenpm:^4.10.3: version: 4.10.3 resolution: axe-corenpm:4.10.3 checksum: 10c0/1b1c24f435b2ffe89d76eca0001cbfff... languageName: node linkType: hard cypress-axenpm:^1.6.0: version: 1.6.0 resolution: cypress-axenpm:1.6.0 peerDependencies: axe-core: ^3 || ^4 cypress: ^10 || ^11 || ^12 || ^13 || ^14 checksum: 10c0/c2cda25355dfa9bd1894357a6231985c... languageName: node linkType: hard yarn-v4.15.0-pnp-dep-resolutionworkspace:.: version: 0.0.0-use.local resolution: yarn-v4.15.0-pnp-dep-resolutionworkspace:. dependencies: axe-core: npm:^4.10.3 cypress-axe: npm:^1.6.0 languageName: unknown linkType: soft可以看到resolution全部以npm:协议指向 registry每个包带10c0校验和linkType: hard表示包内容会被解包/缓存在 Yarn 全局 zip 缓存中。锁文件还客观记录了cypress-axe1.6.0对cypress的 peer 依赖区间^10 || ^11 || ^12 || ^13 || ^14间接佐证了该夹具在发布版本的 Cypress 二进制上运行的设计意图。3. support 文件与 spec真正触发解析的源码cypress/support/e2e.js 的全部内容只有一行import cypress-axe这正是整个测试的核心诱饵Cypress 在加载 support 文件时会用默认 webpack 预处理器把这段源码打包。import cypress-axe让 webpack 必须去解析一个只存在于 PnP 缓存、而非node_modules的包并沿它的依赖图继续解析axe-core。cypress/e2e/spec.cy.js 则是一个模板 specdescribe(template spec, () { it(passes, () { expect(true).to.equal(true) }) })它本身没有任何业务断言说明该测试的通过标准就是打包过程本身不报错——只要 webpack 能同时解析二进制内的构建依赖与 PnP 缓存中的应用依赖spec 就能正常跑完。三、为什么不能像其他 system test 那样常规安装依赖普通 system tests 的依赖是通过 system-tests/scripts/projects-yarn-install.js 用 Yarn v1 统一预装进node_modules的该脚本遍历projects下所有package.json并调用Fixtures.scaffoldProjectscaffoldProjectNodeModules维护缓存。而这个夹具被脚本显式跳过if (project.includes(yarn-v4.15.0-pnp-dep-resolution)) { log(found project yarn-v4.15.0-pnp-dep-resolution, skipping dependency install as this requires corepack for yarn 4) log(this project is an exception and tested inside a docker container with corepack and yarn 4 installed against the built cypress binary) continue }跳过理由在原注释中已经说得很直白该工程需要corepack 配合 Yarn 4才能安装而常规 CI 缓存步骤只具备 Yarn v1 环境因此它被设计为例外在装有 corepack 和 Yarn 4 的docker 容器中、针对构建好的 Cypress 二进制而非源码树直跑执行安装与测试。这正是 README 强调必须作为 binary system test 运行的工程依据只有把 Cypress 打成包含 server 依赖树的二进制后cypress/webpack-batteries-included-preprocessor才会以二进制内部路径的形式存在也才能验证从二进制内解析构建依赖、从 PnP 缓存解析用户依赖这一双路解析场景。四、默认预处理器如何做到构建依赖走二进制、用户依赖走 PnP该夹具之所以有效关键在于 Cypress 的默认预处理器实现。核心代码位于 npm/webpack-batteries-included-preprocessor/index.ts。1. 从二进制内部解析process垫片在getDefaultWebpackOptions()中预处理器通过webpack.ProvidePlugin做全局注入plugins: [ new webpack.ProvidePlugin({ Buffer: [buffer, Buffer], // ... process: require.resolve(process/browser.js), }), ]配合的源码注释直接点名了 PnP 场景对应 issue #27947Due to Pnp compatibility issues, we want to make sure that we resolve to the process library installed with the binary, which should resolve on leafpackages/server/node_modules/cypress/webpack-batteries-included-preprocessorand up the tree. In other words, we want to resolveprocessthat is installed with cypress (or the package itself) and not in the usersnode_modulesdirectory as it may not exist.这段注释把设计意图讲得很清楚在 PnP 项目里用户侧根本没有node_modules如果process垫片试图从用户目录向上解析就会失败所以必须用require.resolve相对预处理器自身所在位置解析保证最终命中随二进制安装的process/browser.js。这样 support/spec 源码里出现的process全局引用都能得到垫片而不会指望用户在 PnP 缓存里额外提供 Node 内置对象。2. 内置 Node 模块的resolve.fallback全表同一函数还通过 webpack 5 的resolve.fallback处理 Node 内置模块process、Buffer、path等在浏览器打包环境中的去向resolve: { extensions: [.js, .json, .jsx, .mjs], fallback: { assert: false, buffer: require.resolve(buffer/), child_process: false, cluster: false, console: false, constants: false, crypto: false, dgram: false, dns: false, domain: false, events: false, fs: false, http: false, https: false, http2: false, inspector: false, module: false, net: false, os: require.resolve(os-browserify/browser), path: require.resolve(path-browserify), perf_hooks: false, punycode: false, process: require.resolve(process/browser.js), querystring: false, readline: false, repl: false, stream: require.resolve(stream-browserify), string_decoder: false, sys: false, timers: false, tls: false, tty: false, url: false, util: false, vm: false, zlib: false, }, plugins: [], }可以观察到一套清晰策略需要真正提供浏览器替代品的内置模块buffer、os、path、process、stream用require.resolve指到预处理器随包携带的浏览器垫片不适用于浏览器、也无需垫片的内置模块fs、child_process、http、net、crypto等统一置为false让 webpack 在源码引用它们时报出清晰的解析错误而非静默失败。这些require.resolve全部相对预处理器自身解析与第 1 点的 PnP 策略一脉相承。此外默认配置还设置了node: { global: true, __filename: true, __dirname: true }并在module.rules里对node_modules内的.mjs使用type: javascript/auto避免 ESM 语法误判、对用户源码用 babel-loader 处理 JSX/TSX 与 mjsgetBabelLoaderOptions中babel/plugin-transform-runtime的absoluteRuntime也指向预处理器自带的babel/runtime同样是依赖不依赖用户目录的思路。3. 从二进制内部解析各类 loader默认 webpack 配置中所有 loader 都通过require.resolve获得绝对路径例如require.resolve(babel-loader)、require.resolve(ts-loader)、require.resolve(tsconfig-paths-webpack-plugin)。在发布形态下这些模块位于二进制内的packages/server/node_modules因此webpack 二进制需要从 Cypress 二进制内部解析它的构建依赖在工程上就是这样落实的。该预处理器对 PnP 的支持并非 Yarn 4 才引入——npm/webpack-batteries-included-preprocessor/CHANGELOG.md 记录了早先的add yarn v2 pnp support to default webpack processor (#17335)以及后续针对 ESM 包内process/browser.js解析的修正#27611说明这条兼容路径经历过长期迭代。4. 默认预处理器在 server 侧的接线在 Cypress server 中file:preprocessor事件默认注册的就是这个开箱即用的 webpack 预处理器。关键接线位于 packages/server/lib/plugins/child/run_plugins.ts其中_getDefaultPreprocessor分支会执行debug(creating webpack batteries included preprocessor with options %o, options) const webpackPreprocessor require(cypress/webpack-batteries-included-preprocessor)也就是说只要用户在cypress.config.js里没有自定义file:preprocessor本夹具正是如此Cypress 加载 support 文件与 spec 文件时的打包工作就会落到cypress/webpack-batteries-included-preprocessor上。此外 packages/server/lib/plugins/child/cross_origin.ts 中还会通过getFullWebpackOptions复用同一套默认 webpack 配置保证跨域等场景下构建口径一致。五、仓库内同族测试先例这个夹具并非孤例。在 system-tests/projects 下还存在姊妹工程yarn-v3.2.0-pnp对应测试定义在 system-tests/test/yarn_v3.2.0_pnp_spec.tsimport systemTests from ../lib/system-tests describe(e2e yarn v3.2 PnP, () { systemTests.it(can compile plugin and test specs, { snapshot: false, browser: electron, project: yarn-v3.2.0-pnp, }) })从测试描述can compile plugin and test specs可以看出PnP 场景的验证对象历来是能不能把 plugin / spec / support 顺利编译出来这一端到端能力。yarn-v4.15.0-pnp-dep-resolution则在版本上跟进到 Yarn 4.15.0并在依赖选择上特意引入cypress-axe → axe-core这条二级依赖链把验证重心落在support 文件内深层的 PnP 依赖解析上可以视为同一策略族在 Yarn 4 时代的延续与加强。六、如何理解与复现这套测试综合 README、projects-yarn-install.js 与 package 配置本夹具的预期运行形态可以归纳为以下流程适合在本地模拟 CI 的 docker 容器准备带 Yarn 4 的环境在容器内启用 corepackcorepack enable并按packageManager: yarn4.15.0激活 Yarn 4.15.0。这一环境前提正是普通 system test 安装通道缺失、需要 docker 单独承载的原因。安装夹具依赖进入夹具目录执行yarn install。由于仓库只固化提交了 yarn.lock安装过程会依据它生成 PnP 状态文件并把axe-core4.10.3、cypress-axe1.6.0装进 Yarn 的 zip 缓存——整个工程不产生node_modules目录。运行 Cypress 二进制以构建好的 Cypress 二进制而非仓库源码直跑对夹具工程执行测试。Cypress 读取 cypress.config.js仅声明fixturesFolder: false无自定义预处理器随后加载support/e2e.js触发默认 webpack 打包。验证点若import cypress-axe及其背后的axe-core都能从 PnP 缓存解析成功、同时二进制内部process等垫片解析正常spec 即可运行通过反之任何一步解析失败都会表现为打包阶段报错可参考packages/server/lib/controllers/spec.ts对 preprocessor 错误统一包装成BUNDLE_ERROR的处理链路。七、小结与工程启示yarn-v4.15.0-pnp-dep-resolution虽然只是一个几行配置的测试夹具但它验证的是 Cypress 在现代包管理器布局下能否继续提供开箱即用的打包能力对用户而言Yarn 4 PnP 意味着项目里没有node_modules、依赖以 zip 缓存形式存在这对任何用node_modules目录行走查依赖的工具都是根本性冲击Cypress 的解法是让默认预处理器把构建期依赖loader、垫片、babel runtime全部锚定到自身/二进制内部的解析路径而把应用依赖交由 webpack 在 PnP 环境中解析由于这种场景无法用 Yarn v1 常规安装来搭建仓库通过跳过常规安装 docker 容器内用 corepack/Yarn 4 针对已构建二进制运行的 binary system test 形态来兜底验证。如果你正在维护或使用 PnP 化的 Cypress 项目本夹具及相关代码是最直接的参照物支持文件里引入任一第三方依赖如cypress-axe即可对照验证你所在版本的 Cypress 默认预处理器是否完整走通了这条双路解析链路。【免费下载链接】cypressFast, easy and reliable testing for anything that runs in a browser.项目地址: https://gitcode.com/GitHub_Trending/cy/cypress创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表