多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Brython 模块导入机制全解析:import 实现原理与 brython_modules.js 优化实战

Brython 模块导入机制全解析:import 实现原理与 brython_modules.js 优化实战 编程语言语言运行时编译器前端【免费下载链接】brythonBrython (Browser Python) is an implementation of Python 3 running in the browser项目地址https://gitcode.com/gh_mirrors/br/brython点击查看免费下载本指南基于仓库内 www/doc/es/import.md与 英文版、法文版 同源展开系统讲解 Brython运行在浏览器中的 Python 3 实现如何像 CPython 一样组织模块与包、在浏览器受限环境下如何通过 Ajax 解析import语句以及如何用brython-cli make_modules生成只包含应用所需模块的brython_modules.js显著减小标准库体积、缩短加载时间。读完本文你将掌握 Brython 应用的目录组织规范、import 解析的完整查找顺序、以及从 全量标准库 到 按需打包 的整套优化流程。一、模块与包的组织方式与标准 Python 一致的布局与 CPython 一样Brython 应用可以按以下规则安装模块或包顶层模块直接放在应用根目录下即一个X.py文件包package放在带有__init__.py文件的目录X/中。例如一个典型应用可以由下列文件与目录组成.bundle-include app.html brython.js brython_modules.js brython_stdlib.js index.html users.py utils.py app __init__.py records.py tables.py此时位于app.html内的 Python 脚本可以直接执行import users import app.records解析import users时Brython 会在脚本所在目录找到users.py解析import app.records时会先定位app/__init__.py包再加载app/records.py。编码要求所有模块必须以 UTF-8 编码保存并且脚本开头的编码声明如# -*- coding: ... -*-会被忽略。这与 CPython 的编码检测规则不同是 Brython 在浏览器环境中对源码编码的硬性约束。站点包site-packages除文档西班牙语版列出的标准库 /X.py/X/__init__.py三项外英文版与法文版还补充了标准库site-packages目录的查找规则Brython 会继续在Lib/site-packages下查找X.py以及在Lib/site-packages/X/下查找__init__.py。从源码 py_import.js 中可以看到make_import_paths()构造的搜索路径path数组正是path [$B.brython_path Lib, $B.brython_path libs, script_dir, $B.brython_path Lib/site-packages]即Brython 运行时目录下的Lib标准库、libsJS 扩展模块、当前脚本所在目录、以及Lib/site-packages。二、浏览器环境下的 import 解析Finder 链与 Ajax 加载2.1 查找顺序要解析import XBrython 采用与 CPython 相同的基本机制依次查找标准库中的模块X脚本目录下的文件X.py脚本目录下子目录X/中的__init__.py即包标准库site-packages目录中的X.py标准库site-packages/X/目录中的__init__.py。2.2 为什么必须依赖 Ajax浏览器无法直接访问本地文件系统因此上述每一次查找文件都对应一次Ajax 调用若指定 URL 处不存在该文件服务器会返回错误信息Brython 据此判断该查找点失败并继续下一处。源码$download_module()py_import.js中可以看到它使用XMLHttpRequest以同步方式请求模块源码并在请求超时5 秒或状态码非 200 时抛出ModuleNotFoundErrorxhr.open(GET, url fake_qs, false) // 同步 Ajax ... $B.RAISE(_b_.ModuleNotFoundError, No module named mod_name )2.3 三个 Finder 的协作从源码结构看Brython 的导入引擎import_engine见 py_import.js维护了一条 meta path依次调用三个查找器Finder的find_spec()方法命中后由对应 Loader 执行create_module/exec_moduleFinder作用启用条件VFSFinder在虚拟文件系统VFS中查找标准库源码页面加载了brython_stdlib.js或brython_modules.js即$B.use_VFS为真StdlibStaticFinder依据 stdlib_paths.js 的静态映射表通过 Ajax 按 URL 加载标准库模块static_stdlib_import选项为真且协议非file:PathFinder沿搜索路径逐个发起 Ajax 请求path/X.py、path/X/__init__.py、path/X.js协议非file:这印证了文档中的描述整个查找链条最终都落到通过 Ajax 探测指定 URL 是否存在文件之上。2.4 页面内多脚本之间的模块导入英文版与法文版文档还补充了一个实用特性如果同一个 HTML 页面内有多个 Brython 脚本已经执行过的脚本可以通过其id被其他脚本导入script typetext/python idmodule def hello(): return world /script script typetext/python from browser import document import module document.body module.hello() /script注意import module中的module正是第一个script标签的id属性值第二个脚本因此可以访问第一个脚本定义的hello()函数。2.5 必须在 HTTP 服务下运行法文版文档特别给出警告如果通过浏览器文件 → 打开的方式直接打开 HTML 页面file:协议上述模块导入不会生效因为 Ajax 请求在file:协议下不可用。本地测试时应先启动 Web 服务器例如在页面所在目录执行python -m http.server然后访问localhost:8000/app.html。这条限制同样体现在源码中make_import_paths()仅在$B.protocol ! file时才将PathFinder加入 meta pathimport_engine在找不到模块时还会附加提示(warning: cannot import local files with protocol file)。三、优化导入性能从 brython_stdlib.js 到 brython_modules.js3.1 默认机制的两个短板上文描述的查找机制存在两个主要问题brython_stdlib.js体积较大文档指出其大小超过 3 MB英文/法文版表述为超过 4 MB。经实际查看仓库www/src/brython_stdlib.js 当前约 4.6 MB与文档描述一致Ajax 调用耗时每次模块查找都可能触发多次网络请求累积起来拖慢应用启动。3.2 使用 brython-cli 生成按需打包的模块文件如果 Brython 是通过pip安装的可以在应用根目录执行brython-cli的make_modules子命令生成一个只包含应用实际使用模块的brython_modules.jsbrython-cli make_modules文档西班牙语版中该命令写作brython-cli --modules这是旧式兼容写法以 setup/brython/main.py 中定义的子命令为准新语法为brython-cli make_modules。从命令行定义setup/brython/main.py可以看出该子命令还支持三个可选参数参数作用-o, --output-path指定生成的模块文件输出路径默认在当前目录生成brython_modules.js--reset将brython_modules.js重置为完整标准库即从brython_stdlib.js复制--modules_paths指向一个以换行分隔的路径列表文件指定除当前目录外还需扫描的模块目录3.3 扫描与生成原理该命令的实现位于 setup/brython/list_modules.py其工作流程值得展开扫描范围程序会遍历应用目录及其所有子目录解析其中的全部 HTML 页面与 Python 脚本。HTML 页面通过BrythonScriptsExtractor提取script typetext/python及script typetext/python src...中的源码list_modules.py并且会正确识别meta charset声明的页面编码提取 import 语句ImportsFinder使用 Python 标准库的tokenize模块而非ast分析源码中的import/from ... import ...从而兼容较旧版本的 CPython——这一点对下面的版本要求至关重要list_modules.py递归收集依赖ModulesFinder.get_imports()会对每个已收录模块继续分析其内部 import将子模块与父包一并加入依赖集合写出 VFS 文件make_brython_modules()最终把模块源码组装成一个 JavaScript 虚拟文件系统对象写入brython_modules.js并设置__BRYTHON__.use_VFS true与调用__BRYTHON__.update_VFS(scripts)list_modules.py。若现有文件内容没有变化程序会跳过重写对应 issue #1471避免无谓修改。3.4 CPython 版本兼容性要求需要注意该工具是用CPython 运行来解析 Brython 源码的因此本地 CPython 版本必须能解析应用中的 Brython 代码语法否则会报语法错误。文档给出的判断标准是如果 Brython 代码中使用了f-string需要 CPython 3.6 及以上如果使用了match / case模式匹配则需要 CPython 3.10 及以上见英文版与法文版。3.5 页面引用替换生成完成后将页面中所有指向全量标准库的标签替换为按需打包文件即可!-- 替换前 -- script typetext/javascript srcbrython_stdlib.js/script !-- 替换后 -- script typetext/javascript srcbrython_modules.js/script四、相关执行选项与测试佐证4.1 影响 import 行为的执行选项除了make_modules本身Brython 页面级/脚本级选项也会直接影响导入行为详见 www/doc/en/options.mdpythonpath以空格分隔的路径列表指定额外搜索模块的目录源码中make_import_paths()会用它替换默认的脚本目录py_import.jsstatic_stdlib_import布尔值默认true控制是否使用 stdlib_paths.js 中的静态映射表来导入标准库模块若页面未加载brython_stdlib.js/brython_modules.js这一机制可让标准库模块仍能通过按 URL 的 Ajax 加载cache设为true时导入模块等 Ajax 请求使用浏览器缓存默认false源码中会附加时间戳参数?v...强制刷新indexedDB默认true允许把brython_stdlib.js/brython_modules.js中模块的编译结果存入 indexedDB避免重复编译对应 py_import.js 中的缓存写入逻辑。这些选项可通过brython-options标签页面级或script标签属性脚本级优先级更高声明。4.2 仓库内的测试验证仓库在 www/tests/test_import.py 中提供了覆盖上述机制的测试用例例如import simple并校验模块文档字符串与类继承对应根目录模块import recursive_import循环导入场景import from_import_test.b/import from_import_test.c包内子模块from delegator import Delegator、from colorsys import *from-import 与星号导入在特定部署布局下从site-packages导入foobar对应 issue 1483。这些用例是验证自身应用 import 行为是否符合预期的参考范本。五、小结Brython 的模块系统在设计上高度对齐 CPython目录即包、__init__.py即包标志、site-packages参与查找但在浏览器环境下把文件系统查找实现为Ajax 探测。理解这一本质后合理使用brython-cli make_modules按需打包即可在保留完整标准库能力的同时把brython_stdlib.js的体积与 Ajax 开销降到最低再配合pythonpath、static_stdlib_import、indexedDB等执行选项可针对不同部署场景进一步调优加载性能。赞分享编程语言语言运行时编译器前端【免费下载链接】brythonBrython (Browser Python) is an implementation of Python 3 running in the browser项目地址https://gitcode.com/gh_mirrors/br/brython点击查看免费下载相关推荐Brython 模块导入机制与 brython_modules.js 优化实战指南Brython 模块导入机制与 brython_modules.js 优化实战指南 BrythonBrowser Python在浏览器中运行 Python编程语言语言运行时编译器前端Stylus 模块化开发指南深入解析 import 与 require 的导入机制、路径解析与实战用法Stylus 模块化开发指南深入解析 import 与 require 的导入机制、路径解析与实战用法 Stylus 作为运行于 Node.js 之上的表前端构建工具Aptos Move 模块、包Package与导入Import机制完全指南Aptos Move 模块、包Package与导入Import机制完全指南 本文以 Move 语言官方文档《Modules, Packages, and区块链Web3上一篇Vulmap与Dismap联动打造完整的web应用识别与漏洞扫描体系下一篇Swift-Tagged 使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表