前端打包工具Mako架构解析|得物技术

一、Mako是什么

Mako是一个新的Web打包工具,适用于Web应用、库和框架。它被设计得快速、可靠且易于使用。Mako已被数百个生产项目中使用。如果你正在寻找一个现代的Web打包工具,Mako是正确的选择。

二、特点

  • 零配置
    从一个JS/TS文件开始,Mako将处理其余部分。开箱即支持TypeScript、Less、CSS、CSS Modules、React、图像、字体、WASM、Node Polyfill等。不需要配置加载器、插件或其他任何东西。

  • 生产级
    Mako是可靠的。它被数百个项目使用,如Web应用、混合应用、小程序(部分)、低代码、Serverless、库开发、Ant Design等。还在数千个旧项目和数千个npm包以及不同版本中测试了Mako,以确保兼容性。

  • 快如闪电
    Mako被设计得快如闪电。在核心打包逻辑中使用Rust,并在Node.js中使用piscina来并行编译文件。在基准测试中,Mako比其他 Rust打包工具和Webpack更快。

  • 热模块替换
    当文件更改时,Mako将自动更新浏览器中的代码。无需手动刷新页面。Mako已集成React快速刷新,当你更改React组件时,它只会更新组件,而不是整个页面。

  • 代码拆分
    Mako内置代码拆分支持。你可以使用动态导入将代码拆分为单独的包,从而减小初始包大小并加快加载时间。Mako具有可配置的选项,你可以用来自定义代码拆分行为。

  • Module Concatenation
    Module Concatenation是一种优化功能,旨在减少包大小和运行时开销。Mako实现了与Webpack优化文档中的实现相当的Module Concatenation。

三、性能测试

通过冷启动、根HMR、叶HMR、冷构建等多个基准测试可以看到,Mako相较于其他构建工具,有着更好的性能。

01.jpg

benchmark基准测试 https://github.com/umijs/benchmark

四、项目架构

entry

02.jpg

现阶段,可以有三种途径来使用Mako构建,分别是:

  • 通过引用Mako的Rust crate来发起,其核心模块均已导出(不过好像未发布到crates.io);

  • 通过引用 Mako的npm包来在nodejs中发起;

  • 通过Mako的cli来发起。

其中,这三种又都是递进关系

  • Rust实现Mako编译的核心逻辑并进行导出。

03.jpg

Mako crate中核心模块导出

  • 通过napi将Mako核心逻辑的Rust代码,经过胶水层,在github workflows中进行交叉编译,编译出多平台的native模块,然后在npm模块中进行引用,再次进行一层封装供用户使用。

04.jpg

使用napi进行编译的胶水层代码

此代码经过编译后,可在nodejs中进行引用,有关napi的具体细节请参考https://napi.rs/cn

05.jpg

交叉编译任务的workflows

06.jpg

js层引用编译好的native模块,封装后暴露给外部使用

07.jpg

经过js层的参数融合后,最终使用native模块进行构建

  • 在前两步已经将功能、暴露均完成的情况,封装一层cli,根据命令,执行构建。

08.jpg

Mako cli中,匹配到build命令,执行封装好的build函数

09.jpg

Compiler

在经过cli端、js端、Rust端的配置融合之后,会得到最终的配置。

10.jpg

基于这些配置,Mako会生成一个Compiler,来执行整个编译流程。

11.jpg

Compiler中存在各种插件来执行任务,插件都拥有如下的生命周期,会在编译过程的各个阶段进行调用。

pub trait Plugin: Any + Send + Sync {
    fn name(&self) -> &str;

    fn modify_config(&self, _config: &mut Config, _root: &Path, _args: &Args) -> Result<()> {
        Ok(())
    }

    fn load(&self, _param: &PluginLoadParam, _context: &Arc<Context>) -> Result<Option<Content>> {
        Ok(None)
    }

    fn next_build(&self, _next_build_param: &NextBuildParam) -> bool {
        true
    }

    fn parse(
        &self,
        _param: &PluginParseParam,
        _context: &Arc<Context>,
    ) -> Result<Option<ModuleAst>> {
        Ok(None)
    }

    fn transform_js(
        &self,
        _param: &PluginTransformJsParam,
        _ast: &mut Module,
        _context: &Arc<Context>,
    ) -> Result<()> {
        Ok(())
    }

    fn after_generate_transform_js(
        &self,
        _param: &PluginTransformJsParam,
        _ast: &mut Module,
        _context: &Arc<Context>,
    ) -> Result<()> {
        Ok(())
    }

    fn before_resolve(&self, _deps: &mut Vec<Dependency>, _context: &Arc<Context>) -> Result<()> {
        Ok(())
    }

    fn after_build(&self, _context: &Arc<Context>, _compiler: &Compiler) -> Result<()> {
        Ok(())
    }

    fn generate(&self, _context: &Arc<Context>) -> Result<Option<()>> {
        Ok(None)
    }

    fn after_generate_chunk_files(
        &self,
        _chunk_files: &[ChunkFile],
        _context: &Arc<Context>,
    ) -> Result<()> {
        Ok(())
    }

    fn build_success(&self, _stats: &StatsJsonMap, _context: &Arc<Context>) -> Result<Option<()>> {
        Ok(None)
    }

    fn build_start(&self, _context: &Arc<Context>) -> Result<Option<()>> {
        Ok(None)
    }

    fn generate_beg(&self, _context: &Arc<Context>) -> Result<()> {
        Ok(())
    }

    fn generate_end(
        &self,
        _params: &PluginGenerateEndParams,
        _context: &Arc<Context>,
    ) -> Result<Option<()>> {
        Ok(None)
    }

    fn runtime_plugins(&self, _context: &Arc<Context>) -> Result<Vec<String>> {
        Ok(Vec::new())
    }

    fn optimize_module_graph(
        &self,
        _module_graph: &mut ModuleGraph,
        _context: &Arc<Context>,
    ) -> Result<()> {
        Ok(())
    }

    fn before_optimize_chunk(&self, _context: &Arc<Context>) -> Result<()> {
        Ok
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值