
Gutenberg 依赖提取的演进与实现wordpress/dependency-extraction-webpack-plugin 深度解析【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenbergwordpress/dependency-extraction-webpack-plugin是 Gutenberg 仓库中负责「外部化 WordPress 共享依赖 生成资产清单文件」的核心 webpack 插件。本文以其 CHANGELOG.md 为时间主线从 1.0.0 的诞生到 6.55.0 的现状完整梳理该插件的每次破坏性变更、能力迭代与 bug 修复并结合 README.md 与 lib/index.js、lib/util.js 源码讲透它的设计动机、默认映射规则、全部配置项与模块打包Script Modules API支持。插件解决了什么问题在 WordPress 生态中开发块编辑器插件时几乎不可避免要import一堆wordpress/*包、React、lodash 等库。这些库早已以wp.*、React、lodash等全局对象的形式存在于 WordPress 站点的运行时中。如果直接把这些依赖打进自己的 bundle会造成重复加载、体积膨胀与版本冲突。这个插件用两个职责解决了上述问题见 README.md外部化externalize把 WordPress 站点上已存在共享脚本/模块的依赖声明为外部依赖webpack 在打包时不再将其编译进 bundle生成资产文件asset file为每个 entry point 生成一个声明依赖清单和版本哈希的*.asset.php或 JSON文件供 PHP 端动态读取。其核心价值在于省去手动维护依赖清单这一极易出错的环节。开发者的源码里写import { store } from wordpress/interactivity构建后依赖清单自动生成WordPress 端wp_enqueue_script时按清单注册依赖即可。该包与 webpack 自带的externals配置功能有重叠README 中也明确说明但本插件是「从编译结果中提取脚本句柄」而externals只负责替换模块引用若不需要依赖清单直接用externals即可。二者可以共存但也可能冲突——例如手动设置{ externals: { wordpress/blob: wp.blob } }会「屏蔽」该模块使其不再出现在依赖清单中。从 CHANGELOG 看插件近七年的演进CHANGELOG.md 记录了从 1.0.02019-05-21到 6.55.02026-09-10的全部变更是理解插件能力边界的权威时间线。以下按阶段梳理其关键里程碑。诞生与第一次破坏性变更1.x → 2.0.01.0.02019 年首次引入该包基础功能即为「外部化 依赖清单」。2.0.02019-09-16一次重要的破坏性变更。插件开始为每个 entry point 生成默认 PHP 格式的资产文件声明该入口的 WordPress 脚本依赖列表同时新增 JSON 输出格式选项。元数据结构与旧版不同文件名也从*.deps.json更名为*.asset.json或*.asset.php——即使选择 JSON 格式引用旧*.deps.json的代码也必须同步更新。正是这次变更确立了今天资产文件的基本形态输出文件.asset.php内容形如?php return array(dependencies array(react), version dd4c2dc50d046ed9d4c063a7ca95702f);2.x合并资产、TS 声明与 webpack 52020 年2.3.0新增combineAssets选项。默认每个 entry 一个资产文件置为true后所有资产信息合并进输出目录下的单个assets.(json|php)文件。2.5.0新增combinedOutputFile选项仅在combineAssets开启时生效允许为合并后的资产文件指定自定义文件名可相对输出目录。2.7.0随包附带 TypeScript 类型声明lib/types.d.ts。2.9.0兼容 webpack 5。3.x版本哈希与共享 chunk2021–20223.0.0Node.js 最低版本提升到 12。3.3.0新增可选的externalizedReportFile选项即如今的externalizedReport。3.5.0连续三项工程化修复值得注意在 Node 17 调用crypto.createHash时改用受支持的 OpenSSL provider修复因 Node 默认 provider 变更导致的报错生成的*.asset.php文件末尾补上换行符版本哈希改为基于输出文件内容计算而不是基于输入文件与 webpack 内部状态——这一改动让哈希更稳定、可复现也直接催生了 6.52.0 对样式文件的处理。3.7.0为共享 chunkshared chunks也输出资产文件。4.x小步快跑2022–20234.0.0Node.js 最低版本升到 14。4.1.0把wordpress/style-engine加入默认外部化列表使 WordPress 6.1 可用wp.styleEngine全局对象。4.10.0内置依赖json2php从^0.0.5升级到^0.0.7用于把依赖对象序列化为 PHP 数组字面量。5.0.0划时代的大版本2024-01-105.0.0 是继 2.0.0 之后又一次大规模破坏性变更移除 webpack 4 支持webpack 5 成为硬性要求移除 Node.js 18 的支持新增 module 兼容资产文件的产出能力对应 WordPress Script Modules API。配套的 package.json 显示peerDependencies为webpack: ^5.0.0engines要求node 18.12.0与 CHANGELOG 完全一致。6.x自动 JSX 运行时、magic comment 与样式哈希2024–20266.0.02024-05-31使用 React 自动运行时automatic runtime转换 JSXNode.js 最低版本提升至 v18.12.0对应 LTS。此前 5.0.0 已通过react/jsx-runtime、react/jsx-dev-runtime的外部化支持为自动运行时铺路见 lib/util.js。6.9.0magic comment 的检测被提前到压缩minification之前这样压缩器无需保留注释即可识别/* wp:polyfill */修复依赖模块存在环时可能导致的无限递归。6.51.0修复 webpack 把动态导入的外部模块拆进独立 async chunk 时未能提取的问题。6.52.0将提取出的样式如style.csscache group 输出纳入 entry 资产文件的版本哈希仅样式变更也能产生新版本号。6.53.0wordpress/kebab-case加入 bundled packages 列表消费者构建时应将其打包进 bundle而不是外部化到一个不存在的wp-kebab-case脚本。Unreleased与6.55.0当前版本继续沿用上述稳定机制。默认外部化规则与 bundle 例外源码级插件的默认映射逻辑集中在 lib/util.js。脚本模式非模块下默认外部化的请求与对应全局对象/句柄如下表摘自 README 并由源码确认请求全局对象脚本句柄babel/runtime/regeneratorregeneratorRuntimeregenerator-runtime句柄映射见 util.js L124-125wordpress/*wp[*]wp-*jqueryjQueryjquerylodash-eslodashlodashlodashlodashlodashmomentmomentmomentreact-domReactDOMreact-domreactReactreact源码中还有几张 README 表格之外的重要映射react-dom/client→ReactDOM句柄映射回react-domreact/jsx-runtime与react/jsx-dev-runtime→ReactJSXRuntime句柄react-jsx-runtime含react-refresh/runtime的请求 →ReactRefreshRuntime句柄wp-react-refresh-runtimewordpress/*请求统一转换为[ wp, camelCaseDash(...) ]数组例如wordpress/api-fetch→[wp, apiFetch]、wordpress/i18n→[wp, i18n]。camelCaseDash只把-字母转大写不会像 lodash 那样把数字后的字母也大写见 test/util.js 对a11y、i18n保持原样的断言。bundled packages 例外源码 lib/util.js 中维护了一个BUNDLED_PACKAGES列表wordpress/admin-ui、wordpress/dataviews、wordpress/fields、wordpress/grid、wordpress/icons、wordpress/interface、wordpress/kebab-case、wordpress/style-runtime、wordpress/ui、wordpress/undo-manager、wordpress/views等。这些包在 WordPress 运行时没有对应脚本命中列表时defaultRequestToExternal返回undefined即不外部化由消费者把代码打包进自己的 bundle——这正是 6.53.0 条目「作为 bundled package」的含义。核心实现原理插件主体在 lib/index.js实现分为三个阶段。阶段一外部化Externalize在apply()lib/index.js中插件创建webpack.ExternalsPlugin并把externalizeWpDeps作为外部化回调注册进去。外部类型根据compiler.options.output.module自动选择import模块模式或window脚本模式。externalizeWpDepsL55-L99的处理顺序是先调用用户配置的requestToExternalModule/requestToExternal模块/脚本模式各用其一若未处理且useDefaults: true级联到defaultRequestToExternal(Module)一旦确定外部化把该 request 记入this.externalizedDeps一个Set供后续生成依赖清单时识别。模块模式下requestToExternalModule支持布尔简写返回true表示「模块 ID 与请求同名」返回false视为未处理L68-L73。阶段二魔法注释检测Magic CommentscheckForMagicCommentsL182-L230在PROCESS_ASSETS_STAGE_OPTIMIZE_COMPATIBILITY阶段扫描入口 chunk 的 JS 内容查找/* wp:polyfill */注释把结果以wpMagicComments元信息写回 asset 的 info 中。在压缩前完成检测对应 6.9.0是为了让压缩器无需保留这类注释。命中后wp-polyfill会被加入该入口的静态依赖L417-L424。测试夹具 polyfill-magic-comment 与polyfill-magic-comment-minified/专门验证这一行为在未压缩/已压缩两种场景下的正确性。阶段三生成资产文件Add AssetsaddAssetsL233-L521在PROCESS_ASSETS_STAGE_ANALYSE阶段运行核心逻辑包括收集依赖遍历入口 chunk含 ConcatenatedModule 的 submodules与 async chunk凡命中externalizedDeps的模块都按其请求映射为脚本句柄脚本模式用mapRequestToDependency模块模式区分静态与动态依赖见下文计算版本哈希用 webpack 输出配置中的hashFunction/hashDigest/hashDigestLength构建 hash对输出文件内容逐一更新——这就是 3.5.0「基于输出内容而非输入文件」的实现L400-L405 的注释解释了为什么不能直接用chunk.contentHash压缩后其不会更新样式文件计入哈希styleFilesByEntryChunkL273-L295把入口 chunk 所属 entry 中所有「无 JS 的兄弟 chunk」典型是style.csscache group的文件并入哈希计算实现 6.52.0 的「仅样式变更也产生新版本」写资产文件默认文件名由 JS 输出文件名替换扩展名得到即foo.js→foo.asset.phpL488-L494脚本模式默认.asset.phpoutputFormat: json时.asset.json使用RawSource直接写入compilation.assets。模块模式下依赖数组中静态依赖排在前面已排序动态依赖以{ id, import: dynamic }对象形式跟在后面L452-L458type: module标记在useModules时为资产数据附加L462-L464。静态/动态的判定依赖hasStaticDependencyPathToRootL534-L609通过遍历 module graph 入边判断模块是否存在一条不经过AsyncDependenciesBlock的静态引入链直通入口——该方法内部用WeakSet/WeakMap做环检测与记忆化这正是 6.9.0 修复无限递归后采用的稳健实现cyclic-dependency-graph 与cyclic-dynamic-dependency-graph/两个夹具即为该场景的回归测试。另外当optimization.runtimeChunk ! false时资产数据会附加handle字段compilation.name 去扩展名的 chunk 文件名L466-L474以便 WordPress 端对共享 runtime 文件只注册一次测试夹具 runtime-chunk-single 展示了runtimeChunk: single的用法。全部配置项详解以下选项均通过构造函数传入默认值取自 lib/index.js 与 lib/types.d.ts。outputFormat类型string默认php资产文件输出格式二选一php或json。PHP 格式通过json2php序列化为?php return array(...);形式见 stringify。outputFilename类型string | function默认null自定义资产文件文件名接受与 webpackoutput.filename相同的取值。源码中通过compilation.getPath(outputFilename, { chunk, filename, contentHash })解析L481-L487因此支持[name]、[contenthash]等模板。测试夹具 option-output-filename 与option-function-output-filename/、function-output-filename/覆盖字符串与函数两种形式。combineAssets类型boolean默认false置true后不按 entry 逐个生成资产文件而是合并到输出目录下的单个assets.(json|php)文件内容为「chunk 文件名 → 资产数据」的映射对象L476-L478、L503-L520。combinedOutputFile类型string默认null仅当combineAssets开启时生效指定合并资产文件的自定义输出路径相对输出目录例如build/combined-assets.php。useDefaults类型boolean默认true置false则完全禁用默认的外部化与句柄映射所有请求都必须由requestToExternal(Module)/requestToHandle处理。injectPolyfill类型boolean默认false强制把wp-polyfill加入每个入口的依赖清单等价于在每个入口手动import wordpress/polyfill;。实现上直接在chunkStaticDeps预置wp-polyfillL314-L316。注意模块模式下此选项不可用README 明确标注因为模块场景没有对应的 polyfill 脚本句柄。externalizedReport类型boolean | string默认false将实际被外部化的依赖以 JSON 数组形式输出为报告文件便于人工或自动化检查。传文件名则输出到该文件传true则使用默认名externalized-dependencies.json常量定义于 L14实现见 L243-L255。该选项的旧称externalizedReportFile出现在 3.3.0 与类型声明中需注意命名差异。requestToExternal类型function(request) string | string[] | undefined仅脚本模式可用。接受模块请求字符串返回全局变量名返回数组可表示对象路径如[wp, i18n]。优先级高于默认映射未处理的请求在useDefaults: true时继续走默认逻辑。典型用法把my-module映射为全局myModule。requestToExternalModule类型function(request) string | boolean | undefined仅模块模式可用。返回的字符串即外部脚本模块 ID通常与请求同名返回true表示「ID 无需变化」返回false或undefined表示不处理。配置项优先于默认逻辑。requestToHandle类型function(request) string | undefined仅脚本模式可用。定制依赖清单中的脚本句柄。不返回字符串时句柄默认与请求同名。典型用法把my-module映射为my-module-script-handle。requestToExternal与requestToHandle配合即可支持任意第三方模块前者把请求映射为全局名决定运行时如何取到对象后者把同一请求映射为句柄决定写进entrypoint.asset.php的字符串。模块打包与 WordPress Script Modules API 对接插件的 v5 引入了模块ESM打包支持。要启用需配合 webpack 配置README 中的完整示例const webpackConfig { ...defaultConfig, // 启用模块编译截至文档撰写时的必要配置 output: { module: true }, experiments: { outputModule: true }, plugins: [ ...defaultConfig.plugins.filter( ( plugin ) plugin.constructor.name ! DependencyExtractionWebpackPlugin ), new DependencyExtractionWebpackPlugin( { // 模块模式使用 requestToExternalModule requestToExternalModule( request ) { if ( request my-registered-module ) { return request; } }, } ), ], };模块模式下插件行为自动适配外部类型变为import依赖以模块 ID而非句柄记录静态/动态依赖区分资产数据附加type: module。默认模块外部化目前只覆盖少数几个请求wordpress/interactivity的实现最特殊lib/util.js返回module wordpress/interactivity形式的外部定义迫使该模块被提升为静态导入interactivity 当前不支持动态导入wordpress/interactivity-router与wordpress/a11y则使用import ...形式。若在模块构建中尝试使用其它wordpress/*脚本会抛出显式错误not supported yet帮助开发者尽早发现问题。模块场景生成的资产文件示例README?php return array(dependencies array(wordpress/interactivity), version dd4c2dc50d046ed9d4c063a7ca95702f);相关测试夹具包括 wordpress-interactivity、wordpress-require、dynamic-import验证 6.51.0 修复的动态导入外部模块提取以及nested-dynamic-import/、cyclic-external-deps/等场景。WordPress 端消费脚本与模块两种姿势构建产物就绪后PHP 端不再需要手写依赖数组直接从资产文件读取以下代码摘自 README传统脚本wp_enqueue_script$script_path path/to/script.js; $script_asset_path path/to/script.asset.php; $script_asset file_exists( $script_asset_path ) ? require( $script_asset_path ) : array( dependencies array(), version filemtime( $script_path ) ); $script_url plugins_url( $script_path, __FILE__ ); wp_enqueue_script( script, $script_url, $script_asset[dependencies], $script_asset[version] );Script Modules APIWordPress 6.5$module_path path/to/module.js; $module_asset_path path/to/module.asset.php; $module_asset file_exists( $module_asset_path ) ? require( $module_asset_path ) : array( dependencies array(), version filemtime( $module_path ) ); $module_url plugins_url( $module_path, __FILE__ ); wp_register_script_module( my-module, $module_url, $module_asset[dependencies], $module_asset[version] ); wp_enqueue_script_module( my-module );注意两个例子都做了file_exists兜底资产文件缺失时退回「空依赖 以源文件 mtime 作为版本号」避免开发环境缓存问题。与 wordpress/scripts 配合的注意点README 明确警告不支持同时实例化多个该插件可能出现非预期结果。若要在wordpress/scripts的默认 webpack 配置基础上扩展必须先过滤掉默认实例再注入自定义实例上文模块示例中的filter写法即为标准做法。这一点也贯穿在测试设计中大量夹具如 wordpress通过requestToExternalModule自定义外部化策略来模拟真实项目。版本选择与升级建议从 CHANGELOG 可以提炼出清晰的版本选型建议目标 WordPress ≤ 6.5 的脚本构建停留在 5.xREADME 的 6.0.0 条目有明确提示因为 6.x 启用了 React 自动运行时早期 WordPress 核心的 JSX 运行时环境不匹配Node 环境5.0.0 起要求 Node ≥ 186.0.0 起要求 Node ≥ 18.12.0LTS低版本 Node 必须同步升级webpack5.0.0 起仅支持 webpack 5peerDependencies: ^5.0.0webpack 4 项目无法使用模块构建仅当使用 webpack 的output.module且面向 WordPress 6.5 的 Script Modules API 时才需要模块模式脚本模式不受影响。总结wordpress/dependency-extraction-webpack-plugin用一套「外部化 资产文件」的机制把 Gutenberg 生态中繁复的依赖共享变成纯自动化的构建行为。从 2019 年的*.deps.json到今天的*.asset.php与 Script Modules API 兼容其演进路线始终围绕两个目标让依赖清单永远与源码同步以及让版本号始终反映真实产物内容。理解其默认映射表、配置项语义与三个阶段的处理流水线无论是直接用wordpress/scripts还是定制自己的 webpack 构建都能在接入时少踩坑、可预期。【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考