一、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相较于其他构建工具,有着更好的性能。

benchmark基准测试 https://github.com/umijs/benchmark
四、项目架构
entry

现阶段,可以有三种途径来使用Mako构建,分别是:
-
通过引用Mako的Rust crate来发起,其核心模块均已导出(不过好像未发布到crates.io);
-
通过引用 Mako的npm包来在nodejs中发起;
-
通过Mako的cli来发起。
其中,这三种又都是递进关系
- Rust实现Mako编译的核心逻辑并进行导出。

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

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

交叉编译任务的workflows

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

经过js层的参数融合后,最终使用native模块进行构建
- 在前两步已经将功能、暴露均完成的情况,封装一层cli,根据命令,执行构建。

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

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

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

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

最低0.47元/天 解锁文章
371

被折叠的 条评论
为什么被折叠?



