Skip to content

Style isolation for demo previewer #7

Closed
@PeachScript

Description

@PeachScript

背景

文档的外部壳和内嵌 demo 的样式表会进行合并且同时在一个 runtime 中被渲染,这意味着,倘若文档外部的壳中有部分全局样式,则会污染到内嵌 demo 的样式,导致开发者在预览阶段看到的效果和生产使用时未必一致,后果十分严重。

备选方案

隔离无非 3 种方案:

iframe 天然隔离

从 Web 层面上来说它似乎就是最佳实践,但在开发 & 使用体验上它却是比较糟糕的:

  1. 我们从浏览器控制台中无法直接看到 iframe 抛出的错误
  2. 倘若我们演示的是 Modal 类型的 demo,这个 demo 在 iframe 中想必会『难以自拔』

ShadowDOM 特性隔离

这是最开始想优先考虑的方案,但在请教 @ikobe 后了解到这里的水非常深。

当一个节点成为 ShadowDOM 后,它的样式表需要手动注入到自己的节点下,这里需要经历编译 demo -> 分析 demo 所引用的全部样式表 -> 编译样式表 -> 存储样式表(也可以字符串变量存在组件中)-> 在运行时插入样式表,目前 webpack 提供的构建钩子中,虽然有能分析到依赖的钩子,但已经处于无法修改构建产物的阶段,如果要继续往这条没人走过的路上走,可能会非常黑,而且不利于后期维护。目前思考下来有如下两个方向还存有突破的可能性:

  1. 在 style-loader 层面做捕获,修改 insertStyle 的行为,但仍然需要看 style-loader 能不能输出 demo 与样式表的依赖关系(尚未调研);
  2. 利用子进程对每一个 demo 做一次单独的构建到 VFS,拿到 css 产物后再回到主进程继续编译 Page Component,可行性应该是没问题,但 demo 一多性能是肯定需要考虑的问题。

为 demo 规避污染源,主动隔离

这是现在 ant.design、Docz 等采用的方案。

原理十分简单,规范外部文档壳样式的编写及应用方式,不写全局样式,对局部样式做大容器的包裹,比如对 markdown 的样式区域用 .markdown 的 className 包裹,这样 demo 区域的样式就不会受到污染。但也存在一些弊端:

  1. 虽然外部文档壳样式不会污染 demo,但倘若 demo 中有全局样式,仍然会污染外部的文档壳;
  2. 倘若同一个页面的两个 demo 之间有样式冲突,也会出现污染。

最终结论

分析下来,从工程角度上讲,最完美的方案肯定是 ShadowDOM;从 ROI 的角度上讲,最适合的方案肯定是主动隔离;至于 iframe,则让它去吧。

考虑到目前 father-doc 正处于 0-1 的阶段,先有可用于生产的产品乃是第一优先级的事,所以在这一阶段中,最终决定采用主动隔离的方案,后续的迭代中再去调研 ShadowDOM 的方式

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions