Closed sorrycc closed 1 year ago
所以,需要调整的是,css import css 时,不能用 js 的 require 的方式。计划这样做,1)在 group chunks 时,遇到 css 时就断掉,不往下分析其依赖,2)在 generate_chunks(具体是在 modules_to_js_stmts)里做 css import css 的合并,当遇到 css module 时(此时的 css module 的 parent module 应该全部都是 js module),以此 css module 为入口找到所有依赖,然后深度优先合并依赖到入口 css 模块里。
这个方案是否会导致尺寸增加,公共 CSS 会被多个 CSS 模块重复合并
@PeachScript
webpack 会重复;esbuild 会做优化,只保留最后出现的那一个。参考 #295 第 4 点。
5、如果没有配 extract_css,会把 css 转 js 输出,每段 css 会通过 style 标签插入到 head 元素里。 6、怎么做 extract_css ? 1)transform_in_generate 时,保持 css 是 css,不转成 js,2)在 generate_chunks(具体是在 modules_to_js_stmts)里遇到 css module 时,按顺序 merge 到一个 css 里并返回,需要注意去重,已 merge 的 module_id 不能重复 merge,只 merge 第一个。
关于 5、6 做了二次调研,同步下相关信息:
Mako 实现思路:
@import
url 移动到最上面几个想到的测试用例,包含与 webpack 及 esbuild 的对比,webpack 使用 mini-css-extract-plugin + cssnano 压缩去重:
/* index.css */
@import 'a.css';
@import 'b.css';
/* a.css */
@import 'c.css';
.a {}
/* b.css */
@import 'c.css';
.b {}
/* index.js 只引入 index.css,mako 结果 */
.a {}
.c {}
.b {}
/* webpack 结果 */
.a {}
.c {}
.b {}
/* esbuild 结果 */
.a {}
.c {}
.b {}
// index.js
import './a.css';
import './b.css';
import './c.css'; // 刻意在最后重复引入 c.css
// mako 结果
.a {}
.b {}
.c {}
// webpack 结果
.c {}
.a {}
.b {}
// esbuild 结果
.a {}
.b {}
.c {}
// a1.js 刻意提升 a.css 的引用层级深度
import './a.css';
// a.js
import './a1';
// b1.js 刻意提升 b.css 的引用层级深度
import './b.css';
// b.js
import './b1';
// index.js
import './a';
import './c.css';
import './b';
// mako 结果
.a {}
.c {}
.b {}
// webpack 结果
.c {}
.a {}
.b {}
// esbuild 结果
.a {}
.c {}
.b {}
MiniCssExtractPlugin 的用例参考:https://github.com/webpack-contrib/mini-css-extract-plugin/tree/master/test/cases
更新了一下 3 个用例在 mako/webpack/esbuild 下的执行结果,目前看 mako 和 esbuild 的行为是一致的,webpack 特立独行可能与其 CSS 实现并非原生内置有关(loader + plugin 实现),所以 mako 先维持目前的逻辑,后续在实际 Umi/Bigfish 项目中看下是否会产生 Breaking Change
7、CSS 的加载
这部分碰到个卡点,需要搜集 cssChunksIdToUrlMap
的数据用来异步加载 CSS,需要跑完所有 chunks 才能知道每个 chunk 是否存在 CSS 以及文件名是什么,最后再生成 entry chunk;但目前 generate_chunks.rs 里是多线程跑的,无法确保 entry chunk 最后生成。
目前想到的方案:
已完成。
How
1、load 里读取文件,parse 里解析成 ast 。
2、transform 里,analyze_deps 之前,处理非 @import url 的 url 依赖引用,支持 inline_limit,小于 xxK 的转成 base64,否则 emit_asset 输出到 dist 目录,不加到 module_graph 里。
3、transform 里还要加个 Visit 做 @import 语句的提前,和 webpack 保持一致。
4、transform_in_generate 里,会做依赖替换。
5、如果没有配 extract_css,会把 css 转 js 输出,每段 css 会通过 style 标签插入到 head 元素里。
js import css 时用这种方式没有问题,比如 a.js -> a.css 。但 css 内部的 import 目前也是用这种 js 的方式进行 require 和 插 style,比如 a.css -> b.css -> c.css,能想到的就会存在一些问题。1)require 有 cache,后面 require 重复的不会执行,而 css 的优先级是以后面的为准的,所以优先级会不对,2)… 。
所以,需要调整的是,css import css 时,不能用 js 的 require 的方式。计划这样做,1)在 group chunks 时,遇到 css 时就断掉,不往下分析其依赖,2)在 generate_chunks(具体是在 modules_to_js_stmts)里做 css import css 的合并,当遇到 css module 时(此时的 css module 的 parent module 应该全部都是 js module),以此 css module 为入口找到所有依赖,然后深度优先合并依赖到入口 css 模块里。
注:1)一个 css 可能既会被 css import,也可能会被 js import,2)注意 cycle dependency 的处理。
6、怎么做 extract_css ? 1)transform_in_generate 时,保持 css 是 css,不转成 js,2)在 generate_chunks(具体是在 modules_to_js_stmts)里遇到 css module 时,按顺序 merge 到一个 css 里并返回,需要注意去重,已 merge 的 module_id 不能重复 merge,只 merge 第一个。
7、CSS 的加载。分两种,1)js 的方式,2)extract_css 的方式。前者没啥好说的,用 js 的方式一次创建 style 标签插入 head 元素即可。extract_css 也分两种,1)entry chunk 的 css,2)async chunk 的 css 。entry chunk 的不需要处理加载,用户在引 js 时也同时引入 css 来解。async chunk 的需要额外的加载逻辑。Webpack 的实现如下。
8、HMR Webpack Runtime 的相关逻辑如下。
9、TODO:Layer + Condition Import。
参考
295
https://github.com/umijs/mako/pull/249