内联JS处理(ES语法降级&内容压缩)(1)

简介: 前言当下大部分现代前端Web工程中,HTML文件大部分都是以public/index.html或<projectRoot>/index.html存在其内容也比较简单,通常像下面这样。

前言

当下大部分现代前端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

image.png

利用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方法进行值的存取操作

image.png


完整代码如下

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

       image.png                                      


同时提供了一个预处理方法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结构描述很朴素

image.png

使用方法如下,也很简单

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

相关文章
|
4月前
|
JavaScript 前端开发 编译器
解锁JavaScript模块化编程新纪元:从CommonJS的基石到ES Modules的飞跃,探索代码组织的艺术与科学
【8月更文挑战第27天】随着Web应用复杂度的提升,JavaScript模块化编程变得至关重要,它能有效降低代码耦合度并提高项目可维护性及扩展性。从CommonJS到ES Modules,模块化标准经历了显著的发展。CommonJS最初专为服务器端设计,通过`require()`同步加载模块。而ES Modules作为官方标准,支持异步加载,更适合浏览器环境,并且能够进行静态分析以优化性能。这两种标准各有特色,但ES Modules凭借其更广泛的跨平台兼容性和现代语法逐渐成为主流。这一演进不仅标志着JavaScript模块化的成熟,也反映了整个JavaScript生态系统的不断完善。
54 3
|
4月前
|
存储 JavaScript 前端开发
Node.js的基本语法
【8月更文挑战第12天】Node.js的基本语法
154 1
|
2月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
3月前
|
缓存 JavaScript 中间件
优化Express.js应用程序性能:缓存策略、请求压缩和路由匹配
在开发Express.js应用时,采用合理的缓存策略、请求压缩及优化路由匹配可大幅提升性能。本文介绍如何利用`express.static`实现缓存、`compression`中间件压缩响应数据,并通过精确匹配、模块化路由及参数化路由提高路由处理效率,从而打造高效应用。
195 14
|
2月前
|
JavaScript 前端开发 大数据
在JavaScript中,Object.assign()方法或展开语法(...)来合并对象,Object.freeze()方法来冻结对象,防止对象被修改
在JavaScript中,Object.assign()方法或展开语法(...)来合并对象,Object.freeze()方法来冻结对象,防止对象被修改
36 0
|
3月前
|
存储 JavaScript 前端开发
[JS] ES Modules的运作原理
【9月更文挑战第16天】ES Modules(ECMAScript Modules)是 JavaScript 中的一种模块化开发规范,适用于浏览器和 Node.js 环境。它通过 `export` 和 `import` 关键字实现模块的导出与导入。模块定义清晰,便于维护和测试。JavaScript 引擎会在执行前进行静态分析,确保模块按需加载,并处理循环依赖。ES Modules 支持静态类型检查,现代浏览器已原生支持,还提供动态导入功能,增强了代码的灵活性和性能。这一规范显著提升了代码的组织和管理效率。
|
4月前
|
JavaScript 前端开发
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
这篇文章是JavaScript基础与实战教程的第一部分,涵盖了JavaScript的基本语法、标识符、数据类型以及如何进行强制类型转换,通过代码示例介绍了JS的输出语句、编写位置和数据类型转换方法。
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
|
4月前
|
JavaScript 前端开发 安全
JS 混淆解析:JS 压缩混淆原理、OB 混淆特性、OB 混淆JS、混淆突破实战
JS 混淆解析:JS 压缩混淆原理、OB 混淆特性、OB 混淆JS、混淆突破实战
236 2
|
4月前
|
前端开发 JavaScript 程序员
前端 JavaScript 的 _ 语法是个什么鬼?
前端 JavaScript 的 _ 语法是个什么鬼?
|
5月前
|
缓存 JavaScript 前端开发
前端框架与库 - Vue.js基础:模板语法、数据绑定
【7月更文挑战第14天】Vue.js 是渐进式框架,以简洁API和高效数据绑定知名。本文聚焦模板语法与数据绑定,解释常见问题和易错点,助力初学者避坑。模板语法中,{{ expression }} 用于渲染值,v-bind/: 用于动态绑定属性。数据绑定涉及文本、属性和事件,注意v-model适用于表单元素,计算属性有缓存。理解正确用法,借助文档和IDE,可提升开发质量和效率。善用Vue.js,打造响应式UI。
169 4