内联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

相关文章
|
5天前
|
JavaScript 前端开发 Java
【JavaScript】基础语法(中)
【JavaScript】基础语法
16 1
|
5天前
|
JavaScript 前端开发 Java
【JavaScript】基础语法(下)
【JavaScript】基础语法
9 1
|
5天前
|
Web App开发 JavaScript 前端开发
【JavaScript】基础语法(上)
【JavaScript】基础语法
9 0
|
5天前
|
前端开发 JavaScript 索引
CSS常见用法 以及JS基础语法
CSS常见用法 以及JS基础语法
14 0
|
5天前
|
JavaScript
JS 基本语法
JS 基本语法
15 1
|
5天前
|
JavaScript 前端开发 C语言
JavaScript编程语法练习
本篇文章是对于javaScript中if ,switch,while ,do-while,,for语法的作业练习.对于我来说也是对自己知识掌握的一种检验.是对js的基础语法进行的一次练习,通过有趣的示例进行练习,使得对于代码能够增加印象,对于知识的掌握更加透彻.
|
5天前
|
JavaScript 前端开发
JavaScript语法(2)
【5月更文挑战第2天】JavaScript语法(2)。
18 3
|
存储 JSON JavaScript
使用JavaScript ES6的新特性计算Fibonacci(非波拉契数列)
使用JavaScript ES6的新特性计算Fibonacci(非波拉契数列)
116 0
使用JavaScript ES6的新特性计算Fibonacci(非波拉契数列)
|
1天前
|
存储 JavaScript 前端开发
从零开始学习Vue.js
Vue.js 是一种流行的前端框架,它使用简单,灵活且易于上手。如果你是一个前端开发者,并想要学习 Vue.js,本文将为您提供一个从零开始的指南。我们将探讨 Vue.js 的基础知识和常用功能,以及如何构建一个简单的 Vue.js 应用程序。