前言
当下大部分现代前端Web工程中,HTML文件大部分都是以public/index.html
或/index.html
存在
其内容也比较简单,通常像下面这样。
<!DOCTYPE html> <html lang="en"> <head> <!-- some meta or link source --> </head> <body> <div id="app"></div> </body> </html>
项目通过构建工具,将编写的"源码"进行一系列操作
后转换成供浏览器可直接运行的js
在产生的HTML文件
中体现的就是通过和标签引入了构建后的资源
其中部分插件会往页面中直接插入内联的JS代码
。
当然也不排除一些项目也会主动通过CDN
引入一些第三方的SDK,然后会在模板中插入一些初始化或者激活相应功能特性的代码
。
针对上面2种情况产生的JS
代码,大部分情况下
是没有通过babel
进行编译的,可能存在一些质量问题(兼容性问题为主)。
如果只是ES语法检查
,可以用前面文章介绍的增强ESCheck工具进行检测。
本文将进一步介绍一下提取HTML inline Code
的多种方法,然后进一步使用SWC
对内联脚本进行压缩
,ES语法转换降级
等等操作。
InlineJS内容处理
用于测试的目标代码如下
<body> <div id="app"></div> <script> const hello = 'hello' </script> <script src="hello.js"></script> <script> const world = 'hello' </script> <script> console.log(hello,world); </script> </body>
目的是将里面的js code
先提取出来,然后将里面的const
简单的替换成var
// 简单转换示例 function simpleConst2Var(code: string) { return code.replace(/const /g, 'var ') }
正则
搞文本内容的处理首先想到的方法,简单的正则如下
/<script>([\s\S]*?)<\/script>/g
利用replace
方法,几行代码就能搞定
function traverseScript(htmlCode: string, transformFn: (v: string) => string) { const rScriptTag = /<script>([\s\S]*?)<\/script>/g return htmlCode.replace(rScriptTag, (all, $1) => { return all.replace($1, transformFn($1)) }) }
局限性就是无法区分出注释,字符串的值,勉强可用。
示例代码地址:inline-code/regexp.ts
GoGoCode
GoGoCode 是一个基于 AST 的 JavaScript/Typescript/HTML 代码转换工具,API是jQuery风格,API还是很简洁好用
其中HTML
的解析使用的是hyntax-yx看上去是 forkhyntax重新发了个版
因此用GoGoCode
同样可以很简单的实现
先生成AST
import $ from 'gogocode' const htmlAST = $(htmlCode, { parseOptions: { language: 'html' } })
GoGoCode 是一个基于 AST 的 JavaScript/Typescript/HTML 代码转换工具,API是jQuery风格,API还是很简洁好用
其中HTML
的解析使用的是hyntax-yx看上去是 forkhyntax重新发了个版
因此用GoGoCode
同样可以很简单的实现
先生成AST
import $ from 'gogocode' const htmlAST = $(htmlCode, { parseOptions: { language: 'html' } })
遍历<script>
节点,其中$scriptNode
节点结构如下,可以直接使用attr
方法进行值的存取操作
遍历<script>节点,其中$scriptNode节点结构如下,可以直接使用attr方法进行值的存取操作
完整代码如下
function traverseScript(htmlCode: string, transformFn: (v: string) => string) { const htmlAST = $(htmlCode, { parseOptions: { language: 'html' } }) htmlAST.find(`<script>$_$</script>`).each(($scriptNode) => { const origin = $scriptNode.attr('content.value.content') $scriptNode.attr('content.value.content', transformFn(origin.toString())) }) return htmlAST.generate() }
代码量和使用正则差不多,但使用AST操作准确性更高,可玩性也强。
hyntax
只提供了AST与Tokens的生成,节点遍历与AST内容转换输出由GoGoCode实现。
示例代码地址:inline-code/gogocode.ts
svelte
Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。
当然不了解这个框架,也不影响理解后续的代码,可以接着往下看
这个是从 AST Explorer transform示例demo中看到的
看了一下demo实现代码
sevlte/compiler提供了直接生成AST的方法compile
import * as svelte from 'svelte/compiler' const AST = svelte.compile(htmlCode).ast const htmlAST = AST.html
同时提供了一个预处理方法preprocess
,可以实现script
,style
与其他标签内容的遍历与修改,最后返回处理后的结果
使用示例如下,其返回值是promise
import * as svelte from 'svelte/compiler' svelte.preprocess(htmlCode, { script(ops) { return { code: transformFn(ops.content) } } })
同样按照上面要求实现script代码的转换
,代码很简洁
function traverseScript(htmlCode: string, transformFn: (v: string) => string) { return svelte .preprocess(htmlCode, { script(ops) { return { code: transformFn(ops.content) } } }) .then((v) => v.code) }
示例代码地址:inline-code/svelte.ts
posthtml
PostHTML 是一个支持使用用 JS 插件转换 HTML/XML 的库。本身只包含
HTML parser
,HTML node tree API
,node tree stringifier
三部分。
插件开发也很简单,其官方的awesome里提供了很多示例的插件,也有可参考的API文档
先通过AST Explorer demo 示例看一下其生成的AST面貌
其AST结构描述很朴素
使用方法如下,也很简单
import posthtml, { Node } from 'posthtml' const result = posthtml() .use(posthtmlPlugin) .process(htmlCode, { sync: true }).html
这里就简单实现一下posthtmlScriptContentTransform
- 利用
match
遍历script
节点 - 使用用户传入的
transformFn
处理content
内容
import type { Node } from 'posthtml' function posthtmlScriptContentTransform(transformFn: (v: string) => string) { return (tree: Node) => { tree.match({ tag: 'script' }, (node) => { if (node?.content?.[0]) { node.content[0] = transformFn(node.content[0].toString()) } return node }) } }
最终使用代码如下
function traverseScript(htmlCode: string, transformFn: (v: string) => string) { return posthtml() .use(posthtmlScriptContentTransform(transformFn)) .process(htmlCode, { sync: true }).html }
示例代码地址
inline-code/posthtml.ts
内联JS处理(ES语法降级&内容压缩)(2):https://developer.aliyun.com/article/1394847?spm=a2c6h.13148508.setting.33.55964f0ez7IHhI