vite编写一个内联js的插件vite-plugin-inline-js
前言
最近有一个想法,就是在使用rem适配大小的时候,往往我们会引入一个用于设置根元素大小的js脚本文件,但是对于这个脚本的处理根据不同情况会有不同的调用方式。
以插件:amfe-flexible为例:
比如我们是一个纯spa项目,一般就会在main.ts
中import引入这个脚本:
import "amfe-flexible";
一般来说,这种做法没什么问题,因为spa的html渲染是js操作的,我们在渲染之前就引入了这个脚本,所以体验上会先通过amfe-flexible设置根元素大小,再进行html渲染,用户体验良好。
随着业务的变化,我们可能会有SSR的需求,首屏loading的需求,这种情况下都会存在非js渲染的html结构,这样用户一进来就能看到一些内容,但是我们使用了rem适配,如果此时amfe-flexible
还在main文件中引入,就会导致用户进来后,内容会发生大小变化,其原因是:
一开始amfe-flexible没有被加载,rem的大小适配都是基于默认根元素html字体大小16px来展示的,当js脚本加载完成,根元素被设置为屏幕宽度/10的字体大小,此时元素重新计算大小重绘。
解决这个问题的做法就是将脚本直接丢在index.html的head中引入,不再main中引入。
<script src="/js/amfe-flexible.min.js"></script>
这种做法最简单,也很方便,但是我又不希望多一个脚本请求,这个脚本文件本身也不大,于是我想到把他做成内联的形式:
<script>
...
</script>
但是这就导致出现了一个很难受的问题,在开发阶段,Prettier 会自动格式化代码,导致index.html变得非常的长,非常不利于开发阅读,于是我萌生了一个想法,能不能让他在编译的时候将<script src="/js/amfe-flexible.min.js"></script>
转换成内联的形式。
于是查了好多文档,都没有现成的插件,要么就是太偏的,不敢用,于是就自己写了一个vite插件来实现这个效果。
插件实现
编写一个脚本文件:_vite-plugins/vite-plugin-inline-js.ts_
内容如下:
import { readFileSync } from "fs";
import { resolve } from "path";
import type { Plugin } from "vite";
export default function vitePluginInlineJs() {
/** 项目路径 */
let rootPath: string = "";
const plugin: Plugin = {
enforce: "pre",
name: "vite-plugin-inline-js",
configResolved(config) {
rootPath = config.root;
},
transformIndexHtml(html: string) {
const reg = /<script src=".*" mode="inline"><\/script>/gi;
const matchResult = html.match(reg);
if (!matchResult) return html;
matchResult.forEach((item) => {
const itemMatchResult = item.match(/src="(.*?)"/);
if (!itemMatchResult) return;
let src = itemMatchResult[1];
if (!src || src.startsWith("http")) return;
if (src.startsWith("/")) src = src.slice(1);
const pathPrefix = resolve(rootPath, "public");
const srcPath = resolve(pathPrefix, src);
const content = readFileSync(srcPath, "utf-8");
html = html.replace(item, `<script>${content}</script>`);
});
return html;
}
};
return plugin;
}
然后再vite中引入并使用
vite.config.ts
import vitePluginInlineJs from "./vite-plugins/vite-plugin-inline-js";
export default {
plugins: [
vitePluginInlineJs()
]
}
然后再index.html中根据格式要求引入脚本:
<script src="/js/amfe-flexible.min.js" mode="inline"></script>
保存后效果如图:
插件会去匹配mode="inline"
的script标签,然后通过fs同步读取到项目public
中的对应脚本文件,然后替换成内联的script标签。
当然这是一个很基础的插件,有想法的可以自己去改改。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据