在 Razzle 中通过 razzle-plugin-php 使用 babel-preset-php 编写「PHP 版」通用 JavaScript 应用【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址: https://gitcode.com/gh_mirrors/ra/razzleRazzle 是零配置的服务器渲染server-rendered通用 JavaScript 应用框架而razzle-plugin-php是 Razzle 官方插件体系中的一员它为 webpack 构建管线接入babel-preset-php让.php文件能够被当作可编译的源代码参与打包。本文以 website/pages/plugins/razzle-plugin-php.md 文档为骨架结合 插件源码 与 Razzle 的插件加载机制讲解安装步骤、配置方式、底层 webpack 修改逻辑及其适用边界。读完本文你将理解 Razzle 插件的工作原理并掌握在自己的项目中接入.php模块的完整方法。官方文档原话“Note this is kind of a joke, but actually works.”这算是个玩笑但确实能跑。本文会如实说明它的实际能力与限制不夸大其用途。插件概览给 Razzle 的构建管线接入 PHP 语法razzle-plugin-php的唯一职责是向 Razzle 的 webpack 配置中注入对.php扩展名的处理规则。它依赖两个核心模块razzleRazzle 主框架负责调用插件的modifyWebpackConfig钩子razzle-dev-utils提供makeLoaderFinder等工具函数用于在 webpack 规则数组中定位特定 loader见 makeLoaderFinder.jsbabel-preset-php将 PHP 语法转译为 JavaScript 的 Babel 预设是实际完成语法转换的引擎。从 package.json 可以看到插件的peerDependencies声明为razzle: 4.2.18与razzle-dev-utils: 4.2.18依赖中固定包含babel-preset-php: ^1.2.0版本号为 4.2.18。该插件的核心实现非常精简整个 index.js 只导出一个modifyWebpackConfig(opts)函数这正是 Razzle 插件协议要求的标准接口——Razzle 在生成 client 与 server 两份 webpack 配置后会逐个调用每个插件的modifyWebpackConfig对配置进行修改。安装使用 Yarn 将插件作为开发依赖安装yarn add razzle-plugin-php --dev如果使用 npm等价命令为npm install razzle-plugin-php --save-dev安装后在项目根目录的razzle.config.js中注册插件// razzle.config.js module.exports { plugins: [php], };plugins数组中的字符串php是简写形式。Razzle 的插件加载器 loadPlugins.js 会依次尝试按以下完整包名解析razzle-plugin-php最常用的命名约定前缀razzle-plugin-php/razzle-plugin后缀形式。因此plugins: [php]等价于plugins: [razzle-plugin-php]。若你的插件是 scoped 包以开头加载器还会尝试scope/razzle-plugin-name这种形式。如果都解析不到Razzle 会抛出Unable to find razzle-plugin-php or ...的错误提示。此外plugins数组还支持对象写法{ name: php, options: {...} }以传递插件选项以及直接内联函数或插件对象用于测试场景详见 loadPlugins.js。插件生效时机modifyWebpackConfig 钩子Razzle 在 createConfigAsync.js 中遍历已加载的插件列表对每个插件检查是否存在modifyWebpackConfig函数for (const [plugin, pluginOptions] of plugins) { // Check if .modifyWebpackConfig is a function. if (plugin.modifyWebpackConfig) { config await plugin.modifyWebpackConfig({ env: { target, dev: IS_DEV, serverless: IS_SERVERLESS }, webpackConfig: config, webpackObject: webpackObject, options: { pluginOptions, razzleOptions, webpackOptions }, paths, }); } }注意env.target会被设置为web客户端或node服务端也就是说该钩子会对 client 与 server 两份配置各执行一次因此.php模块在两端都能被正确解析和打包。插件返回的新config会替换原配置之后 Razzle 还会调用razzle.config.js中用户自定义的modifyWebpackConfig如果存在用户钩子拿到的是插件修改后的配置可以进一步覆盖调整。插件源码逐行解析它到底对 webpack 做了什么来看 index.js 的完整实现use strict; const makeLoaderFinder require(razzle-dev-utils/makeLoaderFinder); module.exports { modifyWebpackConfig(opts) { const config Object.assign({}, opts.webpackConfig); config.resolve.extensions.push(.php); // Exclude from file-loader config.module.rules[ config.module.rules.findIndex(makeLoaderFinder(file-loader)) ].exclude.push(/\.(php)$/); // Dont parse as JS config.module.noParse config.module.noParse ? config.module.noParse.concat([/.php$/]) : [/.php$/]; // Add a custom babel loader (in addition to the one for .js) // making sure to ignore .babelrc config.module.rules.push({ test: /\.php$/, include: config.module.rules.find(makeLoaderFinder(babel-loader)) .include, use: [ { loader: babel-loader, options: { presets: [require.resolve(babel-preset-php)], babelrc: false, }, }, ], }); return config; }, };该实现依次完成四件事注册扩展名config.resolve.extensions.push(.php)让 webpack 在解析import/require时可以省略.php后缀直接命中.php文件。从 file-loader 中排除Razzle 默认配置中用file-loader处理静态资源若.php文件被 file-loader 捕获就会被当作二进制资源复制而非编译。插件通过makeLoaderFinder(file-loader)定位到对应规则把/\.(php)$/追加到其exclude数组中。禁止 JS 解析config.module.noParse追加/.php$/告知 webpack 不要按 JS 语法解析这些文件因为它们的原始语法是 PHP避免解析报错。追加 PHP 专用 babel-loader 规则新增一条test: /\.php$/的 rule其include路径复用 Razzle 已有的 babel-loader 规则通常是src目录loader 使用babel-preset-php预设并设置babelrc: false强制忽略项目.babelrc避免项目级 Babel 配置干扰 PHP 转译。其中makeLoaderFinder是 razzle-dev-utils/makeLoaderFinder.js 提供的工厂函数它返回一个规则匹配函数通过正则[/\\]loaderName[/\\]匹配rule.loader字符串或rule.use数组中的 loader 项从而精确找到 Razzle 内置的file-loader与babel-loader规则无需依赖脆弱的数组下标。由于Object.assign({}, opts.webpackConfig)只做浅拷贝resolve.extensions、module.rules等数组是共享引用——插件是直接原地修改这些数组这也是 Razzle 插件修改配置的标准做法。使用方式在 JavaScript 项目中编写 PHP 模块安装并注册插件后你可以在项目src目录下创建.php文件其内容以babel-preset-php支持的 PHP 语法编写实际是 PHP 语法到 JS 的可编译映射然后在 JavaScript/JSX 代码中像普通模块一样导入// src/index.js import greeting from ./greeting.php; console.log(greeting);?php // src/greeting.php function greeting() { return Hello from PHP!; }关于babel-preset-php的具体语法支持范围以该 Babel 预设的官方说明为准Razzle 插件本身只负责 webpack 配置层面的接入。如上文所述这类用法属于“能跑但偏玩票”性质的实验特性官方文档亦明确提示这一点。适用边界与注意事项仅限开发与实验场景官方文档明确标注 “kind of a joke, but actually works”该插件属于趣味性/实验性扩展不应作为生产级 PHP 与 JS 混编方案。生产环境如需集成真实 PHP 运行时应选择专门的方案如 FastCGI 独立部署这与 Razzle 插件体系无关。不提供 PHP 运行时该插件只负责编译期转译并不会在服务端启动 PHP 解释器运行时能力完全取决于转译产物。忽略.babelrcPHP 文件的转译使用独立的babel-preset-php预设且babelrc: false因此项目根部的自定义 Babel 配置不会作用于.php文件。依赖 Razzle 默认 loader 结构插件通过makeLoaderFinder定位file-loader与babel-loader规则。如果你的razzle.config.js自定义配置大幅改动了这些 loader 的形态例如移除 file-loader插件的查找可能失效。浅拷贝语义插件对opts.webpackConfig做浅拷贝后原地修改共享数组多个插件叠加时要注意执行顺序对同一数组的累积影响。版本匹配插件peerDependencies与 Razzle 主框架版本4.2.18绑定升级 Razzle 时请同步升级插件。相关资源插件文档website/pages/plugins/razzle-plugin-php.md插件源码packages/razzle-plugin-php/index.js插件元数据packages/razzle-plugin-php/package.json插件加载机制packages/razzle/config/loadPlugins.jsmodifyWebpackConfig调用点packages/razzle/config/createConfigAsync.jsloader 定位工具packages/razzle-dev-utils/makeLoaderFinder.js其他 Razzle 插件文档website/pages/plugins【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址: https://gitcode.com/gh_mirrors/ra/razzle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
