GithubHelp home page GithubHelp logo

umijs / mako Goto Github PK

View Code? Open in Web Editor NEW
1.7K 18.0 63.0 9.75 MB

An extremely fast, production-grade web bundler based on Rust.

Home Page: https://makojs.dev

License: MIT License

Rust 67.99% Shell 0.02% JavaScript 22.96% TypeScript 8.51% Just 0.14% CSS 0.22% Less 0.09% HTML 0.03% SCSS 0.05%

mako's Introduction

Mako logo

Mako 🦈

codecov

Mako ['mɑːkoʊ] is an extremely fast, production-grade web bundler based on Rust.

✨ See more at makojs.dev.

Who's using Mako?

  • Web App,Hybrid App, Mini Program (Partly), Low Code, Serverless in Ant Group
  • Ant Design using Mako for its website
  • Umi integrated Mako for its bundling
  • Dumi integrated Mako for its bundling
  • Father integrated Mako for its bundling

Getting Started

Create a new mako project with the following command.

$ npm create mako

Check out the https://makojs.dev/ for more information.

CONTRIBUTING

Read CONTRIBUTING.md.

CHANGELOG

Read CHANGELOG.md.

CONTACT US

Read Feedback on makojs.dev on joining the discussion, contacting the maintainers, and joining the mako contributors.

CREDITS

This project is inspired by:

  • webpack, which inspired lots of ideas of Mako.
  • swc by @kdy1, which powered the parsing, transforming and codegen of Mako.
  • farm by @brightwu, which inspired the tree shaking, plugin system and others of Mako.
  • rspack, which inspired the tree shaking of Mako.
  • oxc-resolver by @Boshen which powered the resolver of Mako.
  • Oxc by @Boshen from which we learned a lot about how to develop efficiently in Rust.
  • biome by @ematipico from which we learned a lot about how to develop efficiently in Rust.

LICENSE

MIT

mako's People

Contributors

afc163 avatar bytemain avatar chessl avatar ctts avatar gin-lsl avatar goo-yyh avatar heden9 avatar hilanxiao avatar hualigushi avatar jackguiyang12 avatar jason89521 avatar jeasonnow avatar jiesia avatar jinbao1001 avatar kiner-tang avatar liangchaofei avatar loveplaycode avatar maple0817 avatar peachscript avatar programmer-yang avatar shulaoda avatar sorrycc avatar stormslowly avatar vagusx avatar whyer11 avatar xiaohuoni avatar xierenyuan avatar xusd320 avatar zhangpanweb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mako's Issues

修改 transform_env_replacer 为 transform_define

问题

现在 env_replacer 只会替换 process.env.xxx,但不支持非 process.env 的替换,相比 define 来说不够通用,比如 if (FOO) {} 想替换 FOO。

解法

1、修改 transform_env_replacer 为 transform_define
2、支持以下场景

FOO: true
process.env.BAR: true
if (FOO) {}
if (process.env.BAR) {}

替换为

if (true) {}
if (true) {}

3、支持 string、number、boolean、object 等格式的值,比如

FOO: "foo"
FOO: 1
FOO: true
FOO: { bar: 1 }

RFC: 使用 Less 的 Bigfish 如何过度到 Mako

Mako 不支持 Less,但是大量的存量项目用 Less;需要解决

整体思路

  1. 替换:将项目中的 import xx from 'xxxx.less' 转换成 import xx from 'xxx.module.css'
  2. build-and-watch 项目启动前,启动一个 less 的 watch 项目,降项目的 less 文件转换成 .module.css 文件

实现

替换

find src -type f \( -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" \) -exec perl -i -pe 's/\.less\b/.module.css/g' {} \;

脚本就是全面,把你 global.d.ts 都改了;另: global.d.ts 放在 src 目录下还是有道理的,他就是源代码,一起修改的时候希望一起变动。

Build and Watch

alias 解决

原先webpack loader 做的事情,现在需要

  1. ~ 别名,比如 import ~npm_pkg/some.less
  2. Bigfish 的 ~@/@/ 别名,~@/styles/example.less

实现一个 less 插件

class AliasFileManager extends less.FileManager {
    loadFile(filename, currentDirectory, options, environment) {
        const aliasedFilename = filename.replace(/^@\//, src).replace(/^~@\//, src).replace(/^~/, npm)
        return super.loadFile(aliasedFilename, currentDirectory, options, environment);
    }
}

class AliasPlugin {
    constructor(options) {
        this.minVersion = [2, 1, 0];
    }
    install(lessInstance, pluginManager) {
        AliasFileManager.prototype.options = this.options;
        pluginManager.addFileManager(new AliasFileManager());
    }
}

module.exports = AliasPlugin

🧑‍💻 🚧 watch

// package.json
    "less": "4.1.3",
    "less-watch-compiler": "1.16.3",

使用这两个依赖,新建 less-watch-compiler 的配置

{
  "watchFolder": "src",
  "outputFolder": "src",
  "plugins": "plugin=./less-alias.js",
  "enableJs": true
}

目前问题,构建的文件是: src/a/b/c.less -> src/a/b/c.css ,但是我们期望的是,

  • 如果需要 CSS Module src/a/b/c.module.css 的方式。
  • 如果是 global CSS 则直接转换

绕过的方式:fork less-watch-compiler 支持配置 outExt (或者直接写死) 生成 c.module.css。global CSS 从用手动的方式修改。

CodeSplitting 思路

调研

主要看了 webpack 的逻辑,获取到如下信息:

  1. 拆分的 chunk 分为 async chunk(比如 dynamic-import)和 sync chunk(比如 entry chunk、vendor chunk),async chunk 的文件名带 .async 后缀
  2. Webpack 的 splitChunks 默认只提取 async chunk 中的公共模块,非 async 模块的公共模块默认会合并到 entry chunk 里(比如 Umi 项目中 react/react-dom 这种就会在 entry chunk 里而不是被拆出去)
  3. 当把提取策略从 async chunk 改成 all 的时候,就会忽略 1 的限制对所有公共模块做提取,但代价是 entry chunk 里的公共模块需要在 index.html 里引入后,entry 才能正常执行,所以 Umi 4 只提取了 async chunk
  4. async chunk 的加载是通过 Promise 实现的,会异步加载所需模块及其依赖(包括依赖的依赖)所在的 chunk 数组,等 chunk 就绪后再执行后续逻辑,示例代码:
Promise.all(
  /*! import() */[
    __webpack_require__.e(660),
    __webpack_require__.e(621),
    __webpack_require__.e(238)
  ]).then(__webpack_require__.bind(__webpack_require__, /*! ./lazy */ 238));
  1. entry chunk 里对 sync chunk 的加载是在应用启动前加载的,比如 vendor chunk
  2. 拆哪些 chunk 取决于 splitChunks 配置,每个分组对应一个 chunk 拆分策略,通过 test 匹配模块来源,通过 name 指定 chunk 名称,这是 Umi 4 里按依赖拆分的配置示意:
{
  cacheGroups: {
    vendors: {
      test: /[\\/]node_modules[\\/]/,
      priority: 10,
      chunks: 'all',
      name(module: any) {
        const match = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/);
        if (!match) return 'npm.unknown';
        const packageName = match[1];
        return `npm.${packageName
          .replace(/@/g, '_at_')
          .replace(/\+/g, '_')}`;
      },
    },
  },
}

思路

内容已过期,以下方最新内容为准

mako 现阶段只提取 async chunk 中的公共模块,会从按 npm 包名_版本维度拆 chunk(depPerChunk 策略)开始实现,大致思路:

1. entry chunk 不做处理,因为暂时不拆 sync chunk
2. 增加 try_split_module 方法,先判断依赖是否要从当前 chunk 拆出去(模块来源是 node_modules 且当前 chunk 不是自己,就要拆出去;后续其他拆分策略也在这个方法里实现),如果要拆出去,则返回模块的 deps 数组(新 chunk 为 create_chunk 返回的 deps 数组,已有 chunk 为仅包含模块自己的 deps 数组,因为其他 deps 已经处理过了)
3. 在遍历 async chunk 的依赖时,如果需要把该依赖拆出去,则将其作为 external_dependencies(应该可以和现在 dynamic_entries 的设定合并),且不再执行 chunk.add_module
4. 通过 edges 记录 async chunk 对 external dep chunk 的依赖关系
5. module_graph 上对 module.info 新增 pkg 字段,存储当前模块文件关联的 package.json,便于执行代码拆分策略
6. 在生成 runtime 代码的时候,对有上游依赖的 async chunk 使用 rqeuire.ensure 来确保前置依赖加载完成后再执行该 chunk

附录

resolve 抛错时需要给出完整 require 链路

目前是这样,

thread '<unnamed>' panicked at 'build module failed: Resolve "fs" failed from "/private/tmp/sorrycc-uoJMjW/foooo/node_modules/[email protected]@cron-parser/lib/parser.js"', crates/mako/src/build.rs:93:29
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fatal runtime error: failed to initiate panic, error 5
[1]    74101 abort      OKAM=  build --dev

但是不知道 cron-parser 是谁依赖的,如果有完整的依赖链路,会更方便排查问题。

_interopRequireDefault resolve 到了 esm 版本的文件

image

@babel/runtime/helpers/interopRequireDefault resolve 到了错误的 @babel/runtime/helpers/esm/interopRequireDefault.js 这个文件,实际上应该要是 @babel/runtime/helpers/interopRequireDefault.js
image

master 分支

cargo run --bin mako examples/with-antd --mode production

优化 svg 的处理

问题

现在所有 svg 文件都会返回两项内容,包含不必要的内容,有点浪费。

export const ReactComponent = ...;
export default url | base64;

方案

我的想法是这样。

transform js 时,处理 .svg 的 import 语句,如果 specifier 是 ReactComponent,就把 import source 加上 ?ReactComponent 查询。

import { ReactComponent } from './foo.svg';
import x from './foo.svg';
⬇️⬇️⬇️
import { ReactComponent } from './foo.svg?ReactComponent';
import x from './foo.svg';

load 阶段,针对是否有 ReactComponent 会返回不同的内容。

同时,./foo.svg 和 ./foo.svg?ReactComponent 由于有不同的查询参数,会自动被当成不同的 ModuleId 。

注意,用户也可能这么用。

import svg, { ReactComponent } from './foo.svg';

with-umi example 压缩时报错

复现步骤如下。

$ cargo build --release
$ time ./target/release/mako examples/with-umi --mode=production
 INFO mako::build: build
 INFO mako::build: build module graph
 INFO mako::build: build time in main thread: 0ms
 INFO mako::build: module count: 185
 INFO mako::build: build done in 64ms
 INFO mako::generate: generate
 INFO mako::group_chunk: generate_chunk
 INFO mako::transform_in_generate: transform all modules
 INFO mako::generate_chunks: generate chunks
 INFO mako::minify: minify
thread 'main' panicked at 'index out of bounds: the len is 3588 but the index is 3592', /Users/chencheng/.cargo/registry/src/github.com-1ecc6299db9ec823/swc_common-0.31.12/src/syntax_pos/hygiene.rs:472:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
./target/release/mako examples/with-umi --mode=production  0.31s user 0.08s system 301% cpu 0.129 total

RFC:Umi + Mako Server

1、在 bundler-okam 里实现一个基础版的 bundler-webpack/server 。

  • 不需要 ws server,直接连 mako 的
  • cors
  • compression
  • serve static for dist(因为 mako server 的产物是落盘的)
  • connect-history-api-fallback
  • https
  • dev banner

2、自动添加入口文件,连接 Mako 的 Socket Sever 。

const socket = new WebSocket('ws://127.0.0.1:3000/__/hmr-ws');
socket.addEventListener('message', onUpate);

几个问题,

1)port 哪里来?Umi 层探测好可用的端口之后传给 Mako。
2)这段代码怎么自动添加?让 Mako 的 entry 支持数组,然后在 Umi 层修改 entry 添加一个临时的 client.js 加上述逻辑。

3、检测配置,遇到如下配置时提示不支持并退出

  • mfsu
  • 大量 webpack 相关的配置…

4、preset-umi/commands/dev.ts 里识别 MAKO 开启时用 bundler-mako 的 dev 方法启动。

if (process.env.OKAM) {
  const { dev } = require(process.env.OKAM);
  await dev(opts);
}

TreeShaking 思路

TreeShaking module

  • module_id 模块的ID
  • side_effects 是否包含副作用
  • stmt_graph 语句的依赖关系图
  • used_export 当前模块被依赖到的 export 语句,反之就是要被删除的语句
  • module_system 当前的模块系统类型:esm、cjs、混合

实现思路

  1. module_graph.toposort() 拓扑排一下,主要是看看哪些模块被用到了,以及分析循环依赖
  2. 针对循环依赖的模块设置为 sideEffects
  3. 针对入口模块设置为 sideEffects
  4. 针对不是JS的模块、以及他们的依赖也设置为 sideEffects
  5. 包含了 external 的模块也设置为 sideEffects
  6. 将原始模块重新创建为 treeShaking 模块
  7. 针对不是 esm 的模块,默认全部导出(commonjs的),(没法treeShaking)
  8. 针对有副作用的模块,分析 export、import
    1. 分析 import 语句的过程:
      1. 找到当前依赖的模块
        1. 如果当前模块不是JS、或者是external的,则跳过处理
        2. 如果当前使用模块的姿势是 import “xxx”,这里有可能是 specifiers.is_empty 或者是 Namespace,则认为当前模块是 UsedExports:ALL 并且包含副作用
        3. 如果是 named export,则提取当前的 specifiers
        4. 如果是 default export,则提取当前的 specifiers 为 default
    2. 分析 export 语句的过程(这里只包含重新导出的部分,re-export)
      1. ….
  9. 分析不含副作用的模块
    1. 如果当前模块不包含任何 usedexport,则认为当前模块是可以被删除的
    2. 开始删除无用的声明
    3. 类似上面的分析过程,对删除声明后的代码进行分
  10. 动态加载的模块
    1. 入口模块设置为副作用模块,usedexport:all
  11. 删除刚刚分析出来的无用模块

CSS import 资源文件时不支持不带 ./ 的方式

.title {
  background: url(big.jpg);
}

现在会报 Resolve 找不到。

.title {
  background: url(./big.jpg);
}

加上 ./ 才正确。

而实际上,CSS 里通过 url 的方式引用资源,是不需要带 ./ 的,也会从相对路径开始找。

axios 里的 else if 分支需要 shake 掉

https://unpkg.com/browse/[email protected]/lib/defaults/index.js

function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    // For browsers use XHR adapter
    adapter = require('../adapters/xhr');
  } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    // For node use HTTP adapter
    adapter = require('../adapters/http');
  }
  return adapter;
}

其中 ../adapters/http 中包含大量的 node 代码。

HMR + useModel 报错

也有可能和 HMR 无关。

复现步骤,

1、初始化 ant-design-pro 项目

bunx @ant-design/pro-cli create myapp
cd myapp

修改 package.json 中的 @umijs/max 版本为 4.0.72 !!!

pnpm i
umi config set mfsu false
rm -rf src/global.less (因为不支持 less)
config/config.ts 里注释掉 OpenAPI 相关配置

2、切换 Mako 分支到「sorrycc-7q50」

git checkout sorrycc-7q50
pnpm i
cargo build --release
cd crates/node && pnpm run build

3、用本地的 max,因为有依赖 umijs/umi#11343 这个改动。

4、在 ant-design-pro 绑定 bundler-mako 执行 dev 命令。

OKAM=/path/to/umijs/marko/packages/bundler-okam/index.js 本地的max dev

5、启动后修改 src/pages/Welsome,报错如下。

image

CSS 支持嵌套语法和报错改进

复现步骤,

cat <<EOF >index.ts
import './index.css';
EOF
cat <<EOF >index.css
.a { .b { color: red }}
EOF
mako ./ --mode production

报错如下,

 INFO mako::build: build
 INFO mako::build: build module graph
 INFO mako::build: build time in main thread: 0ms
 INFO mako::build: module count: 2
 INFO mako::build: build done in 5ms
 INFO mako::generate: generate
 INFO mako::group_chunk: generate_chunk
 INFO mako::generate: transform all modules
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: UnexpectedToken(Delim('.')), loc: Some(ErrorLocation { filename: "", line: 0, column: 4 }) }', crates/mako/src/transform_in_generate.rs:62:89
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

两个问题,

  • 不支持嵌套语法(postcss 是支持的,lightencss 应该也有配置开启的)
  • 报错信息看不出是哪个文件出错了

css modules 不支持 :global scope

复现步骤,

.a {
  color: red;
}

:global {
  .b {
    color: green;
  }
}

会报错,

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: SelectorError(EmptySelector), loc: Some(ErrorLocation { filename: "", line: 3, column: 2 }) }', crates/mako/src/transform_in_generate.rs:62:89
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

:local 应该也同理,我没测。

Compiler.update 实现思路

接口定义

Compiler.update 接受一个指令集合,并且完全信任这个指令集合。

Array<{ path: string, type: Type }>

enum Type {
  // 文件修改
  modify,
  // 文件新增
  add,
  // 文件删除
  remove
}

Compiler.update 返回的结果包含上述指令结果中,模块的变化情况

{
  add: ModuleId[], // 模块真的有新增,(如果只是新增边则不算,一定要真的新增文件)
  removed: ModuleId[], // 模块真的被删除了(如果只是删除边则不算,一定要真的删除了文件)
  modified: ModuleId[], // 模块被修改了 (新增或删除遍,认为是修改)
}

通过 devServer 把这组结果发送到 Runtime,Runtime 完全根据上述结果,来决定特定 ModuleId 的模块如何处理。比如重新动态加载某个模块(通过 hmr 专用的 http 接口)

🌰 一

举个例子:

当前的依赖关系:
module_a <- module_b
module_c <- module_b

接受的指令:
Compiler.update([{
  path: module_a,
  type: modified
}]);

修改依赖关系为:
module_a <- module_d

返回的结果:
{
  add: [module_d],
  modified: [module_a]
}

因为 module_c 还在依赖 module_b,所以 module_b 不算被 remove,只是依赖关系消失了
而 module_d 是首次新增进来的,所以认为是 add

🌰 二

当前的依赖关系:
module_a <- module_b

接受的指令:
Compiler.update([{
  path: module_a,
  type: modified
}]);

修改依赖关系为:
module_a <- module_d

返回的结果:
{
  add: [module_d],
  modified: [module_a]
}

此时也不做 module_b 的卸载 ,因为当前没有收到 b 的删除指令。此时考虑到 module_b 的依赖树可能非常复杂,如用户注释了一行 import * from 'antd',在没有明确收到删除指令的情况下,没有必要把整颗树(可能有上千个模块)的模块都卸载掉。并且此时在用户把 import * from 'antd' 加回来的情况,我们只需要 modified: [module_a] 就可以。

针对 modified 这个指令的处理流程

  • 解析指定 module 的结果,得到依赖关系
  • 对依赖关系进行 diff 处理,分析出 add[]、remove[]
  • 针对 add[] 的处理:针对这个依赖做完整的 module_graph 构建
  • 针对 remove[] 的处理:针对这些依赖做依赖关系的删除,不删除模块。也不再进入依赖模块进行再次分析。

针对 add 这个指令的处理流程

  • 同上述针对 add[] 的处理过程

针对 remove 这个指令的处理流程

  • 删除对应的模块,已经断开对应的依赖关系。如果此时有其他模块仍然在依赖他,则需要给出报错信息。

支持 stats

建议步骤。

1、调研 webpack 的 stats 结构,简化结构,可以先只包含和产物相关的基本信息
2、产出 rfc,结构如何,计划怎么做,发 issue 以「RFC:」为前缀
3、研发
4、补充用例

建议时间:下周三之前。

优化 base64 处理

基于 #184 想到的。

问题

1、现在写死了 data:image/{};base64,{} 为 image 类型,不支持非 image 的场景
2、image 的场景有些也不直接是后缀,比如 #184 改的 svg,比如 .jpeg 和 .jpg 都应该是 image/jpeg

方案

data: 后面接的是 mimetype,应该找个 mimetype 库,就可以实现为通用的了。

css 里 @import remote url 时应该保留

比如:

@import "https://fonts.googleapis.com/css?family=Open+Sans";
.a { color: red; }

现在会报错

build module failed: Resolve "https://fonts.googleapis.com/css?family=Open+Sans" failed from "/private/tmp/sorrycc-weCqJ6/index.css"

期望应该是保留 @import "https://fonts.googleapis.com/css?family=Open+Sans"; 不作为依赖处理。

支持生成 sourcemap

概要

sourcemap 文件会记录产物文件和源代码的映射关系,一个 *.map 文件的基本结构如下:

{
  "version": 3,
  "file": "bundle.js", // 产物文件
  "sources": [ // 源代码文件
    "../src/utils.js",
    "../src/index.js"
  ],
  "sourcesContent": [ // 数组, 每一项是 sources 中文件的源代码
    "export function print(content) {\n  console.log(content);\n}\n",
    "import { print } from './utils';\n\nprint('Hello World');\n"
  ],
  "names": [ // 用于优化的字段, 可不关注
    "console",
    "log"
  ],
  "mappings": "yBACEA,QAAQC,ICCJ" // 位置的映射信息
}

*.map 文件中记录了所有模块的文件路径、源码内容以及映射关系。要生成 sourcemap 文件,就需要将所有模块的信息放入一个 swc_common::SourceMap 实例 cm 中。

而不是现阶段为每一个模块都生成一个 cm,这样会导致每一个 cm 的 sources 只有一项,且最终无法拼接。

详细设计

新增全局共享的 swc_common::SourceMap 实例

Context 中添加共享数据 sourcemap

pub struct Context {
    pub meta: Meta;
}

pub struct Meta {
    pub js: JsMeta,
    pub css: CssMeta,
}

pub struct JsMeta { //  js sourcemap
    pub cm: Arc<SourceMap>,
}

pub struct CssMeta { //  css sourcemap
    pub cm: Arc<SourceMap>,
}

cm 中添加源文件信息

parse 阶段使用 context.meta.js.cm.new_source_file() 添加文件,而非创建新 cm:

fn parse(path: &str, content: &str, context: &Arc<Context>) {
    let fm = context
        .meta
        .js
        .cm
        .new_source_file(FileName::Custom(path.to_string()), content.to_string());

    // ...
}

等构建出模块依赖图后,所有模块的信息都会被添加到 context.meta.js.cm 以及 context.meta.css.cm 中。

生成 sourcemap

需要对每一个 Chunk 都生成一个 .map 文件,追加 sourceMappingURL 到每个 Chunk js 文件末尾:

buf.append(&mut "\n//# sourceMappingURL=index.js.map".as_bytes().to_vec());

生成最终的 sourcemap 文件:

fs::write(format!("{}.map", output.display()), &file.sourcemap).unwrap()

预见的问题

.map 文件中 sources 文件路径

这是目前实验阶段生成出的一份 sourcemap 文件(基于 examples/normal 项目):

{
  "version": 3,
  "sources": [
    "<index.js>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected]/node_modules/scheduler/index.js>",
    "</Users/jess/Code/Jess/mako/examples/normal/index.css.ts>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.production.min.js>",
    "</Users/jess/Code/Jess/mako/examples/normal/assets/umi-logo.png>",
    "</Users/jess/Code/Jess/mako/examples/normal/foo.ts>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected]/node_modules/react/index.js>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected]/node_modules/react/cjs/react.development.js>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.development.js>",
    "</Users/jess/Code/Jess/mako/examples/normal/assets/mailchimp-unsplash.jpg>",
    "</Users/jess/Code/Jess/mako/examples/normal/index.tsx>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected]/node_modules/react/cjs/react.production.min.js>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/index.js>",
    "</Users/jess/Code/Jess/mako/examples/normal/foo.css.ts>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/@[email protected]/node_modules/@swc/helpers/esm/_interop_require_default.js>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected]/node_modules/scheduler/cjs/scheduler.development.js>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/client.js>",
    "</Users/jess/Code/Jess/mako/node_modules/.pnpm/[email protected]/node_modules/scheduler/cjs/scheduler.production.min.js>"
  ],
  "names": [],
  "mappings": "" // 这里被我隐藏了
}

sources 中的文件路径有些问题:

  • 都被 < ... > 包裹住了
  • 路径应该是相对路径而非绝对路径,这是因为在开发服务下 http://localhost:8080/Users/jess/Code/Jess/mako/examples/normal/index.js 会找不到。

css sourcemap

当前 mako 会将 css 转为 js,所以上述 sources 中出现了一些 *.css.ts 文件,这些文件不能被正常找到。

这一块建议先不做处理,后续支持生成单独的 css 文件后即可解决该问题。

Mako Next

WIP

目标

1)打磨功能,发布 RC 版
2)接入 Bigfish 并落地 50+
3)接入 Minifish 并落地 50+

里程碑

7 月
完成 Code Splitting
完成 Tree Shaking
完成第一轮功能打磨
Bigfish 官网切换为 Mako

8 月
完成第一个 Bigfish 项目接入

9 月
Mako 官网和文档
完成 5+ 项目接入

10 月
Mako 发布 RC 版
Mako 作为 Bigfish 的默认脚手架

11 月
推广 Mako 到业务线项目

MAKO 下一步

1、两个重要功能 code splitting(@辟殊) 和 tree shaking(@禾登) 需要先完成基础版本实现,有个能用的版本,完成之后我们才可以把 mako 落到真实项目中进行验证。由于辟起休假,code splitting 先交给辟殊。

2、部分重要功能需要打磨成最终版。多看社区方案及其用例,然后系统梳理思路,考虑最终态应该如何,同时考虑各种边界场景的处理、报错的处理、单测和集成测试的补充。我觉得需要打磨的功能包括:

loader @云谦
css @灏辰
hmr @辟殊 (优先级在 code splitting 之后)
svgr @杰司
cli 交互设计和错误处理 @云谦

3、功能补充

stats + manifest (后者依赖前者,参考 webpack 做简化处理) @油油
content hash

4、Bugfix

TODO

5、补 example,拿 Mako 写真实项目 @钱凌雅 @韩泽邦

Mako x ChatGPT
Mako x Hackernews
Mako x Bigfish + Ant Design Pro + Tech UI + Tern

6、工程化

less to css @韩泽邦
#240 (comment)

功能大图

  • INFRA
    • test
    • benchmark
    • scripts
      • 发布脚本 (TODO)
    • examples
  • DX
    • performance
      • compile on demand (MAYBE)
      • fs cache (MAYBE)
    • error handling
      • runtime error overlay (TODO)
    • cli
  • UX
    • code splitting(IMPLENTING)
    • tree shaking(IMPLENTING)
  • FILE TYPES
    • assets
    • css
    • javascript
    • json
    • wasm
    • svg
    • text including md (MAYBE)
    • mdx (MAYBE)
  • FEATURES
    • runtime
    • hmr
    • content hash (TODO)
    • alias
    • externals
    • source_map
    • minify
    • css modules
    • css autoprefixer
    • css extract
    • copy
    • node_polyfill
    • top level await (IMPLEMENTING)
    • manifest (TODO)
    • stats (TODO)
    • polyfill (MAYBE)
    • case_sensitive_detect (MAYBE)
    • analyzer (MAYBE)
    • plugin (MAYBE)
    • loader (MAYBE)
    • html (MAYBE)
    • es output (MAYBE)
    • dead code detect (MAYBE)
    • mfsu like (MAYBE)
  • COMMUNITY
    • tailwindcss (TODO)
  • INTERNAL
    • ?
  • TOOLS
    • less to css (TODO)
  • INTEGRATE
    • umi / bigfish
      • bigfish cli performance
    • minifish (TODO)
    • browser (MAYBE)

提供 provider plugin,完善 node 补丁方案

问题

node 使用里,比如 process 和 Buffer 的使用并不需要 require 来声明,直接用就可以。比如。

if (process) 1;
Buffer.from('foo');

现在的补丁方案里没有支持这种场景,会导致运行时报错。

解法

1、实现类似 webpack 中的 ProvidePlugin,遇到匹配的没有声明过的 identifier,注入一份依赖
2、配置里加上 provide 配置,默认配置如下

provide: {
  Buffer: ['buffer', 'Buffer'],
  process: [nodeLibs['process'], 'default'],
}

参考

RFC:node polyfill 方案完善

现有问题

不用 bundler-okal 单独跑 mako 时,遇到 node 相关的依赖库(比如跑 with-antd)会出错。

思路

1、fork node-libs-browser 到 node-libs-browser-okam,新增 polyfill 文件夹,为有补丁的 node 模块提供单独的文件,比如 polyfill/assert.js

module.exports = require('assert/');

2、整理一份有提供补丁的模块列表如下,添加 alias 到 node-libs-browser-okam/polyfill 下,比如 assert 应该是 node-libs-browser-okam/polyfill/assert

assert
buffer
console
constants
crypto
domain
events
http
https
os
path
process
punycode
querystring
stream
string_decoder
sys
timers
tty
url
util
vm
zlib

3、bunder-okam 里添加 node-libs-browser-okam 依赖,并添加 node-libs-browser-okam 的 alias

4、root package 添加 node-libs-browser-okam 的 devDependency,确保本地开发 mako 时不报错

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.