
webpack 5 如何用 module.parser.javascript.parse 替换默认 JS 解析器【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through loaders, modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpackwebpack 5 默认用 acorn 解析 JavaScript 模块。如果你希望在构建时换用其他解析器例如 oxc、meriyah可以通过module.parser.javascript.parse传入一个自定义解析函数让 webpack 在解析每个 JS 模块时调用它。本文基于仓库中的 examples/custom-javascript-parser 示例说明解析函数的签名约定、三种参考实现、两种配置位置和验证方式。仓库当前版本为 5.110.3见 package.json该示例要求 Node.js 主版本 20见 test.filter.js。解析函数要满足的契约在 lib/javascript/JavascriptParser.js 中parse选项的类型是/** typedef {(code: string, options: ParseOptions) ParseResult} ParseFunction */即函数接收两个参数并返回一个结果对象code: string——模块源码options: ParseOptions——包含sourceTypemodule | script、ecmaVersion、locations、comments、ranges、allowHashBang、allowReturnOutsideFunction等字段返回值ParseResult——{ ast, comments }其中ast是 estree 的Programcomments是Comment[]。当配置了自定义parse函数时webpack 内部在JavascriptParser._parse(code, options, customParse)中直接调用customParse(code, options)见 JavascriptParser.js 的_parse实现。未配置自定义函数时传入的默认选项值为/** type {ParseOptions} */ const defaultParserOptions { sourceType: module, ecmaVersion: latest, ranges: false, locations: false, comments: false, allowHashBang: true };实现自定义解析器时有两点约定来自示例代码的注释AST 不需要完整的 position/loc 信息。oxc 实现的注释说明webpack 会从节点偏移量和源码文本自行推导行列位置webpack derives line/column locations from node offsets and the source text itself。webpack 的 magic-comment 查找会读取comment.range所以返回的注释对象需要带start/end或range信息。三种参考解析实现示例目录 internals/ 提供了三个可直接复用的实现文件分别对应 acorn默认、oxc、meriyah。acorn默认解析器的等价实现acorn-parse.js 的完整逻辑use strict; const acorn require(acorn); /** import { Comment, SourceLocation } from estree */ /** * import { * ParseOptions, * ParseResult * } from ../../../lib/javascript/JavascriptParser */ /** * param {string} sourceCode the source code * param {ParseOptions} options options * returns {ParseResult} the parsed result */ const acornParse (sourceCode, options) { /** type {(Comment { start: number, end: number, loc: SourceLocation })[]} */ const comments []; const ast /** type {import(estree).Program} */ ( acorn.parse(sourceCode, { ...options, onComment: options.comments ? comments : undefined }) ); return { ast, comments }; }; module.exports acornParse;要点options直接透传给acorn.parse只有options.comments为真时才通过onComment收集注释否则返回空数组。oxc可选分支oxc-parse.js 使用oxc-parser包use strict; const oxc require(oxc-parser); /** * Oxc has no location API — none is needed: webpack derives line/column * locations from node offsets and the source text itself. ASI positions are * likewise read from the source, so no semicolon collection is required. * param {string} sourceCode the source code * param {ParseOptions} options options * returns {ParseResult} the parsed result */ const oxcParse (sourceCode, options) { const result oxc.parseSync(file.js, sourceCode, { astType: js, range: true, sourceType: options.sourceType module ? module : script, // ts-expect-error no types experimentalRawTransfer: true }); const comments /** type {(Comment { start: number, end: number })[]} */ (result.comments); // webpacks magic-comment lookup reads comment.range for (const comment of comments) { if (!comment.range) comment.range [comment.start, comment.end]; } return { ast: /** type {Program} */ (/** type {unknown} */ (result.program)), comments }; }; module.exports oxcParse;这里options.sourceType module被映射为 oxc 的module / script注释的range由start/end补齐保证 magic-comment 查找可用。meriyah可选分支meriyah-parse.js 需要把 webpack 的选项翻译成 meriyah 自己的选项名use strict; const meriyah require(meriyah); const meriyahParse (sourceCode, options) { /** type {(Comment { start: number, end: number, loc: SourceLocation })[]} */ const comments []; const ast /** type {import(estree).Program} */ ( meriyah.parse(sourceCode, { ...options, module: options.sourceType module, loc: options.locations, onComment: options.comments ? (type, value, start, end, loc) { if (type SingleLine || type MultiLine) { comments.push({ type: type SingleLine ? Line : Block, value, start, end, range: [start, end], loc }); } } : undefined }) ); return { ast, comments }; }; module.exports meriyahParse;注意两处字段映射options.sourceType module对应 meriyah 的module开关options.locations对应loc开关注释类型也从 meriyah 的SingleLine/MultiLine归一化为 estree 的Line/Block。三个实现分别require了acorn、oxc-parser、meriyah三个包在你的项目中使用哪个实现就需要在项目中安装对应的依赖只用 acorn 实现则无需新增解析器依赖acorn 本就是 webpack 默认解析器。在 webpack 配置中替换默认解析器配置方式见 webpack.config.js 和 schemas/WebpackOptions.jsonJavascriptParserOptions.parseFunction to parser source code.。有两个作用位置全局替换写在module.parser.javascript.parse对所有 JS 模块生效按模块替换写在module.rules的某条 rule 的parser.parse中只对该 rule 的test匹配到的模块生效。示例配置oxc 一条另两条 meriyah/acorn 结构相同仅解析函数和输出文件名不同use strict; const oxcParse require(./internals/oxc-parse.js); /** type {import(webpack).Configuration} */ const config { mode: production, optimization: { chunkIds: deterministic // To keep filename consistent between different modes (for example building only) }, output: { filename: oxc.[name].js }, module: { // Global override parser: { javascript: { parse: oxcParse } } // Override on the module level, only for modules which match the test // rules: [ // { // test: /\.js$/, // parser: { // parse: oxcParse // } // } // ] } }; module.exports config;两点说明optimization.chunkIds: deterministic是示例自带的配置其注释说明用途是在不同模式间保持文件名一致例如只做 building 时与解析器替换本身无关可按需保留或去掉。output.filename写成oxc.[name].js这种前缀形式只是为了区分三套输出你自己的项目保持默认[name].js即可。执行构建示例的源码入口是 example.js内容是一个静态 import 加一个动态 import用来同时覆盖同步依赖与import()代码分割两条解析路径import { increment as inc } from ./increment; var a 1; inc(a); // 2 // async loading import(./async-loaded).then(function (asyncLoaded) { console.log(asyncLoaded); });仓库统一用cd example目录 node build.js的方式构建各示例见 examples/buildAll.js。只构建本示例时执行cd examples/custom-javascript-parser node build.js在自己的项目中则直接使用上面的配置运行你平时的 webpack 构建命令即可无需修改 webpack 本身。结果验证README.md 给出了示例构建的 stats 输出。以生产模式Production mode文档示例输出为例asset output.js 2.01 KiB [emitted] [minimized] (name: main) asset 655.output.js 121 bytes [emitted] [minimized] chunk (runtime: main) 655.output.js 24 bytes [rendered] ./async-loaded ./example.js 6:0-24 ./async-loaded.js 24 bytes [built] [code generated] [exports: answer] import() ./async-loaded ./example.js 2 modules ./example.js 6:0-24 chunk (runtime: main) output.js (main) 457 bytes (javascript) 5.34 KiB (runtime) [entry] [rendered] ./example.js main runtime modules 5.34 KiB 8 modules ./example.js 2 modules 457 bytes [built] [code generated] [no exports] [no exports used] entry ./example.js main webpack X.X.X compiled successfully上面是文档示例数值以你项目实际编译为准。判断替换是否生效可以看两点构建正常完成webpack X.X.X compiled successfully无解析报错动态import(./async-loaded)仍然被识别为独立的异步 chunk655.output.js对应import() ./async-loaded依赖——这说明自定义解析器返回的 AST 被 webpack 正常消费模块依赖与代码分割逻辑没有因为换解析器而丢失。README 同时给出了未优化模式Unoptimized的对照输出可用于确认 tree shaking、模块合并等优化行为与默认解析器一致。限制与实现时的注意点返回结构必须完整ParseResult必须包含astestreeProgram和comments数组。即使不需要注释也要返回空数组acorn 实现中options.comments为假时即返回空数组。注释要带位置信息webpack 的 magic-comment 查找读取comment.rangeoxc 实现的注释原话是 webpacks magic-comment lookup readscomment.range所以自定义实现的注释对象至少要带start/end或补齐range。选项名需要映射ParseOptions的字段是 webpack 侧的约定sourceType、locations、comments等不是所有解析器都用同名参数。meriyah 示例展示了module: options.sourceType module、loc: options.locations的映射方式oxc 示例展示了sourceType到module / script的映射。自写解析器时按同样思路逐字段对齐。AST 无需完整 loc位置信息可由节点偏移加源码推导自定义解析器不必强制收集 position但需要能给出节点偏移oxc 实现显式开启了range: true。该示例目录的 test.filter.js 限定 Node.js 主版本 20 才运行在自己的环境中使用该示例时保持 Node.js 20 及以上可避免不必要的干扰。【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through loaders, modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpack创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考