Shuey猫舍

文章摄影项目关于
https://cdn.shuey.fun/images/2022/0508/title_bg.webp

Codepage项目开发

2022-05-08| 阅读量: | 评论:

  • Web
  • Vite
  • Iframe
@アシマ / Ashima

一个用来在前端展示简单的网页代码的项目,项目地址:Codepage。开发过程中主要使用到的知识是:iframe,script。

iframe

起初页面的功能设计打算参考别人的博文中:

  1. 使用真的src地址渲染演示结果,通过与iframe通信实现reload等功能;
  2. Scss通过在线接口进行编译,本地重载iframe中的css;
  3. 编辑器中使用emmet可以快速的开发html、css;

在实际的开发过程中,查看MDN iframe文档中查看到srcdoc这在html5中新的属性。这个避免使用src的一个麻烦,比如插入<script src="">, 在src中需要使用document.createElement创建脚本对象,然后设置属性,最后插入文档中的对应位置。

如果直接使用element.innerHTML插入script会导致脚本资源不会被加载,详细原因参考:Can scripts be inserted with innerHTML?。换成srcdoc之后使用模板字符串替换一下就会刷新页面,怎么简单怎么来(Vue SFC Playground中也是这么做的)。

1
2
3
4
5
6
7
h("iframe", {
    frameborder: '0',
    allow: 'fullscreen',
    sandbox: 'allow-forms allow-modals allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation',
    srcdoc: views.value,
    name: 'result-show',
});

这段是渲染结果的VUE的代码,主要功能是允许iframe中的演示结果使用尽可能多的沙盒功能同时也允许iframe内部调用全屏函数。

console

将在 iframe 中 console 输出的内容同步显示到主界面上。

script

script标签有属性type,如果这个type的类型可以是MIME或是module,如果是其他的则被当成数据对待。

所以我在当前hugo主题中添加palyground,渲染的时候把需要插入显示的代码放入script中,因为我还不太会用hugo去生成复杂的逻辑,比如gzip压缩等,所以目前的逻辑还是先把代码存储到页面,由JavaScript生成网页。

1
2
3
<script type="data" name="{{ .Get 0 }}" array="{{ .Get 1 | default false }}">
    {{ .Inner }}
</script>

这个方法在很多的WebGL教学中也被使用,将顶点着色器和片源着色器的代码也放在script标签中,当然这个也就是我们学习的时候使用,去翻看一些3D引擎的代码,着色器都是动态生成的代码(这群人玩字符串都要优化到魔怔了)。

LESS和Scss支持

起初打算使用在线接口去实现,但是大家都是各种的CORS身为懒人的我自然懒得去尝试哪个网站的跨域完全开放的,也懒得去搭建一个代理服务。于是想到刚刚上大学的时候看到了LESS直接在HTML中直接使用,开始思考直接在前端引入代码进行编译。这点LESS很容易实现,毕竟他有直接的JavaScript的实现。

问题来到了Scss那边,目前找到最好的解决方案是三年前的项目,直接编译到WASM的Scss的编译器。于是目前LESS和Scss都实现了在前端的编译,由于编译、页面重载是耗时的操作,于是在编辑代码的变动处增加防抖限制。

参数压缩

其实这个在实际的项目中没有太多的作用,因为仔细想了想,项目的目的就是分享百十行内的代码分享,目前使用get请求的参数传递,从目前的测试看下来,不同浏览器(IE在我这除名)的get请求大概可以支持65536(或者32768)个字符,加上代码分享的时候使用base64编码后加入get请求,大概可以容纳500行代码,足以实现项目的设计目标。

但是中间都走了一段时间的弯路,也要记录下来给个纪念。

Haffman

如果想对哈夫曼编码有直观的认识,这个网站->Haffman Tree Generator;

最开始我在思考base64编码的结果当中重复的字符串比较多,实际的字符串出现的字母数量不多,比较长点的路径长度才到9,实际测试过程中, 压缩率大概到50%1,加上相比全文可以忽略不计的字典,压缩率还是相当可以,压缩后可以容纳大约1000行代码。

但是这个对于我在博客中使用还是很麻烦的,也很不方便之后其他人集成(虽然没有人会用这个项目就是啦~)。因为不仅仅我内部需要实现一套Haffman编码的逻辑,插入的地方也需要一套编码逻辑。

Gzip

其实最开始我是把目光投向Brotli,但是Brotli编码没有找到比较好的浏览器解决方案。后来发现比较新的接口CompressionStream和DecompressionStream,这俩个接口可以实现在web端直接压缩、解码数据,使用起来十分方便,如下是编解码的所有代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
export const arrayToBase64String = (a) => window.btoa(String.fromCharCode(...new Uint8Array(a)));
export const base64StringToArray = (s) => new Uint8Array([...window.atob(s)].map(char => char.charCodeAt(0)));
export const compress = (string, encoding='gzip') => {
  const byteArray = new TextEncoder().encode(string);
  const cs = new CompressionStream(encoding);
  const writer = cs.writable.getWriter();
  writer.write(byteArray);
  writer.close();
  return new Response(cs.readable).arrayBuffer();
}
export const decompress = (byteArray, encoding='gzip') => {
  const cs = new DecompressionStream(encoding);
  const writer = cs.writable.getWriter();
  writer.write(byteArray);
  writer.close();
  return new Response(cs.readable).arrayBuffer().then(function (arrayBuffer) {
    return new TextDecoder().decode(arrayBuffer);
  });
}

Gzip在代码中的压缩率可以到20%2,这是一个相当恐怖的压缩率,对比一下,Haffman这种没有窗口没有默认字典的压缩方式的确是粗枝大叶。

这里也要吐槽一下,MDN的中文文档更新速度实在是太慢了,得亏是高中的英语能力还是支持的了我看懂英文文档的!!这个Compress接口在中文文档中都无法找到(写这个博客的时候想要贴中文介绍链接,我居然找不到)!还不了解怎么去给MDN打工做翻译啊,感觉翻译这个的中文文档需要翻译很多和这个相关联的页面。

总结

其实项目没有多少代码,估计四百行代码就实现了配置等所有的功能。当时考虑到应用比较小,打算自己写点组件锻炼自己,没有使用组件库。

之所以代码可以这么简短,还是因为有类似Monaco Editor、VueUse、Sass.js这些已经完善的基础功能,我只会傻傻的把他们拼接到一起,做实现自己的一个小想法。

最后是发现来来回回我还是绕到了WASM,这个我在大学时候尝试用来写毕业论文的工具。当时用这个实现了一个数字电路模拟器,用C++写了很多界面渲染的代码,以及电路的状态管理。第一次接触这个技术是2019年的时候,当时觉得学习这个需要熟悉JavaScript还需要熟悉C++,对于我这样的懒人大抵是没有机会了。现在再看看,Scss这边的功能也是依赖于这项功能,包括如今火起来的Rust前端框架,也大多依赖与这项功能。同时我自己的另外一个想法,也不得不使用WASM来解决问题。

问题有俩点,前后端对图像的渲染不一致;运行时的后端渲染功能现在必须要用前端实现。

前后端渲染不一致很正常,一般图元信息都是前端来渲染,和后端用的的工具库都不一样,想要调整成一样的多少有点麻烦。这个时候我就在思考能不能让前端的工具库被我们的后端使用呢?这个肯定可以,而且方法特别多,但是接着就到了第二个问题来了。

这个时候需要我们来接手后端的工作,如果使用传统的前端代码去做,那我们还是写俩套,于是不得不去想办法使用WASM让后端的代码可以直接在前端被运行,最少的代码改动。加油,目前已经在加班加点工作了,预计月底可以做到把后端的渲染移植到前端来吧!!到时候再继续写博文记录吧。


  1. Haffman编码在前篇博文WebGL学习中的压缩率为41%; ↩︎

  2. Gzip在前篇博文WebGL学习中的压缩率为16%; ↩︎

TypeScript装饰器(旧)

2024-09-30 10:14

Web DICOM本地渲染方案探索

2022-04-29 17:25

Shuey Yuen

Shuey Yuen

百工之人,不恥相師

目录

  • iframe
  • console
  • script
  • LESS和Scss支持
  • 参数压缩
    • Haffman
    • Gzip
  • 总结

相关文章

  • TypeScript类型体操(基础)
  • TypeScript装饰器(5.0)
  • TypeScript装饰器(旧)
  • Web DICOM本地渲染方案探索

分类

  • Web 9
  • WebGL 2
显示全部

聚合标签

TypeScriptDecoratorDesign PatternWASMWebGLAlgolia
显示全部

© 2017-2025 Shuey Yuen/ admin / store

皖ICP备2023022130号-1

🌞 浅色 🌛 深色 🤖️ 自动