Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Prism.js动态加载所需语言包

Prism.js动态加载所需语言包

作者头像
用户6256742
发布于 2022-07-06 06:58:35
发布于 2022-07-06 06:58:35
3.5K00
代码可运行
举报
文章被收录于专栏:网络日志网络日志
运行总次数:0
代码可运行

前言

Prism是一款非常好用的前端代码高亮插件,很多开发者搭建的文章、博客分享网站中都使用到了prism.js来做代码高亮,但是在官网的下载网站选完了主题和插件后却犯了难:如果选择语言包,如果全选那么体积将近600kb如果选少了害怕以后不够用,还要来补。其次,基本上只有语言包支持Node.js环境,插件基本都是基于DOM实现没有对Node.js环境进行兼容。于是有了一个想法:通过API接口将语言包动态返回,根据前端传来的参数,主题+语言包+插件拼接后返回给前端的script和link标签。

于是我实现了这个功能,并且应用于自己的网站上,网站可以选择主题进行代码高亮,最重要的他会将页面中代码块使用到的高亮语言包进行拼接返回,实现了按需分配。(其实也不是难事,官网download页面也是这样)

最终效果:

实现

需要进行保存的:

  1. components中的prism-core,这个是核心包
  2. components中的其他文件是语言包
  3. themes文件夹下是主题包css
  4. plugins下是插件包
  5. components.json是语言依赖包里面记录了有哪些语言包、依赖关系、别名

下面的查找我也以这五个包名来代替需要返回的文件内容。返回时也是按照核心包(js)+主题(css)+语言包(js)+插件(css、js)进行拼接,下面是我的存放格式,在读取文件时我会以public的绝对路径进行读取,prism下是本文代码高亮相关的。

我们先将GitHub源代码克隆下来,里面有全套的主题包、语言包和插件包到手后最好先写个代码将开发中的未压缩版本删除,只保留min版本。

下面贴出我实现的代码:

整个API接口的完整代码(Express)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import express, { NextFunction, Response, Request } from "express";
import fs from "fs";
import cache from "@/common/middleware/cache";

const app = express();
const router = express.Router();
/** 
 * 定义使用的主题和插件
* !如果使用了工具栏中的按钮,一定在先定义toolbar
*/
const config = {
  themes: "tomorrow",
  plugins: [
    "toolbar",
    "line-highlight",
    "line-numbers",
    "inline-color",
    "copy-to-clipboard",
    "show-language",
  ],
};
/** prism代码高亮的相关配置*/
const components: any = JSON.parse(
  fs.readFileSync("public/prism/components.json").toString()
).languages;

const cors = fs.readFileSync(`public/prism/prism-core.min.js`).toString();
const themes = fs.readFileSync(`public/prism/themes/prism-${config.themes}.min.css`).toString();
const plugins = config.plugins.map(item => {
  return {
    css: fs.existsSync(`public/prism/plugins/${item}/prism-${item}.min.css`)
      ? fs.readFileSync(`public/prism/plugins/${item}/prism-${item}.min.css`).toString()
      : "",
    js: fs.existsSync(`public/prism/plugins/${item}/prism-${item}.min.js`)
      ? `/**插件:${item}**/${fs.readFileSync(`public/prism/plugins/${item}/prism-${item}.min.js`).toString()}\n`
      : "",
  };
});

let language: { [key: string]: string } = {};
fs.readdirSync(`public/prism/language`).forEach(item => {
  language[item.replace(`prism-`, "").replace(`.min.js`, "")] = fs
    .readFileSync(`public/prism/language/${item}`)
    .toString();
});

/**
 * 根据传来的单个类型递归返回全部依赖类型,并且排序
 * @params type {string} 类型
 * @return typeArray {string[]} 所有依赖到的类型
 */
function getAllType(type: string) {
  let typeHub: string[] = [type]; //存储类型(先将原始类型存进来)
  function requireType(_type: string) {
    let languageRequire: string | string[] = components[_type]?.require;
    if (!languageRequire) {
      return; //第一个语言没有依赖就可以直接返回了
    }
    if (typeof languageRequire == "string") {
      typeHub.unshift(languageRequire);
      requireType(languageRequire);
    } else {
      languageRequire.forEach(item => {
        typeHub.unshift(item);
        requireType(item);
      });
    }
  }
  requireType(type);
  return typeHub;
}

router.get("/high-light/:type",cache, async (req: Request, res: Response, next: NextFunction) => {
  if (req.params.type == "css") {
    res.setHeader("Content-Type", "text/css;charset=UTF-8");
    res.write(`${themes}\n${plugins.map(item => item.css).join("\n")}`);
    res.end();
    return;
  }

  let _language = (req.query.languages + "")
    .split(",")
    .map(item => {
      //如果没有类型,将使用别名,转化为正确名称
      if (language[item]) return item;
      let aliasIndex = Object.values(components).findIndex((index: any) => {
        if (!index.alias) return false;
        return typeof index.alias == "string" ? index.alias == item : index.alias.includes(item);
      });
      //既没有别名,又没找到语言的返回false
      return aliasIndex != -1 ? Object.keys(components)[aliasIndex] : false;
    })
    .filter(item => !!item)
    .map(item => getAllType(item as string))
    .flat()
    .map(item => {
      return language[item] ? `/**language:${item}**/\n${language[item]}` : "";
    })
    .join(`\n`);

  res.setHeader("Content-Type", "text/javascript;charset=UTF-8");
  res.write(`
  /**个人博客:blogweb.cn**/
  ${cors}\n${_language}\n${plugins.map(item => item.js).join("\n")}
  `);
  res.end();
});
export default router;

讲解

先将定义一下主题和使用到的插件,然后将这些css和js的包都加载出来,挂到一个对象上。对文件进行读取,在前端带参数请求时可以直接以key:value的形式进行查询、拼接、返回。有的插件只有JS没有CSS,需要进行一下判断,没有CSS就返回一个空字符串,不会影响拼接,并且在合并是无需判断。

在源代码里面有个components.json的文件也是需要保存的,里面记录的各个语言包相互的依赖关系(require属性),以及语言包的别名。我们在编写代码时需要对这种情况进行处理。

我们需要对依赖关系进行处理,同时将依赖包引进,并且依赖包也需要返回给前端。根据components.json内依赖关系进行递归查询,一直到不在有require属性了就返回数组。

到了这里基本的工具函数就写完了,开始编写路由,路由的参数不需要和我的一样(我的不是很标准),我们可以在一个接口内通过参数将CSS和JS都能进行处理,我们判断req.params类型如果是CSS就直接将主题(themes)的CSS和使用到的插件的CSS进行拼接返回即可。

如果是JS就要相对麻烦一些要判断依赖关系,不过我们在之前已经写好工具函数了使用req.query.languages获取前端需要的语言包(参数格式样例:css,typescript,cpp),转为数组后先查找别名,判断之前以key:value形式保存的语言包对象上有没有对应的属性, 没有的话在components.json中进行查找所有语言的require属性,看看是否可以和前端需要的语言匹配,如果找到了是前端返回的语言别名,那就改成标准名称,否则说明Prism.js没有提供对应的语言包,就返回false,然后在后面给过滤掉。

最后这一步就是拼接、合并了,合并后整个语言包的JS为数据格式join一下转为字符串(拼接过程中其实不在需要判断了,直接返回 language[item]就行),上面已经将false过滤掉了。

然后就是最后一步了,将核心包、语言包、插件,按照顺序拼接返回出去。

测试

按照路径先测试css,只有5kb

测试JS路径,以html,typescript为例,只有33kb,因为在语言包的拼接上留了注释,可以ctrl+F搜索一下,只有这两个语言包和相依赖的包,例:ts>js>c-like,算是html一个四个包,前端页面完美运行。

使用

我使用了ORM框架操作数据库,所以直接在文章表中加了个虚拟字段,在服务器端判断文章中的代码高亮使用了什么语言包,可以根据项目实际情况来决定在哪里进行语言判断。同时判断方法需要看HTML结构而定,我之前使用过很多富文本编辑器和Markdown编辑器来写博客,每个编辑器代码块结构又略有不同,所以只能考虑多种情况,麻烦一点。

请求CSS、JS资源包需要在客户端创建link和script标签来加载。

思路

  1. 用户端创建link和script标签携带参数向服务器获取对应的语言包
  2. 读取文件夹,将主题包、插件包中使用的主题或者插件进行读取,将语言包文件读取并保存在对象中
  3. 获取各个语言包的依赖关系,并且保存到数组中
  4. 在遍历语言包数组时对语言包对象上没有的进行别名查询,如果确定是使用了别名,那就改成标准的名字,如果确定是语言包转给你没有成语言,那就返回false,然后过滤掉
  5. 判断type类型进行核心包(js)+主题(css)+语言包(js)+插件(css、js)进行拼接
  6. 返回拼接的CSS和JS字符串
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
利用Prism.js脚本工具实现网页代码高亮效果
如果我们是站长相关的网站博客,如果需要引用一些脚本代码的时候一般看到的都是代码高亮效果,这样的用户体验更好一些。我们要实现代码高亮的方法有很多中,比如WordPress也有代码高亮插件或者是手动实现CSS样式来实现代码高亮。在这篇文章中老蒋要分享的是Prism.js小工具可以实现页面的代码高亮效果。
老蒋
2021/12/27
6.5K0
利用Prism.js脚本工具实现网页代码高亮效果
Joe一款基于Typecho博客的双栏极致优化主题
Github下载地址:HaoOuBa/Joe: A Theme of Typecho (github.com)
Breeze.
2022/04/11
1.7K0
Joe一款基于Typecho博客的双栏极致优化主题
组件库构建过程
最近在项目内部创建了一个vue组件库,希望通过组件库的形式,统一项目中组件的逻辑和样式,让代码的复用性更强。
Keller
2021/12/14
5420
组件库构建过程
Webpack——从基础使用到手动实现(万字长文)
这个其实不用多说了,如今的前端项目哪里还有用不到打包工具的呢,而webpack又作为打包工具中的王者我们又有什么理由不去搞明白它呢。
coder_koala
2020/07/15
1.1K0
Webpack——从基础使用到手动实现(万字长文)
Vue3(Vite) 通过 prism.js 实现代码高亮并实现Mac风格
prismjs漂亮的代码语法高亮插件 极致易用:引用 prism.css 和 prism.js,使用合适的 HTML5 标签(code.language-xxxx),搞定! 天生伶俐:语言的 CSS 类是可继承的,所以你只需定义一次就能应用到多个代码片段。 轻如鸿毛:代码压缩后只有 1.6KB。每添加一个语言平均增加 0.3-0.5KB,主题在 1KB 左右。 快如闪电:如果可能,支持通过 Web Workers 实现并行。 轻松扩展:定义新语言或扩展现有语法,或者新增功能都非常简单。 丰富样式:所有
超级小的大杯柠檬水
2023/05/10
2.7K1
Vue3(Vite) 通过 prism.js 实现代码高亮并实现Mac风格
[Skill]GitBook搭建
从https://nodejs.org/en/下载并安装Nodejs,安装完后可通过终端命令node -v检验是否安装成功。
TOMOCAT
2021/12/16
2.1K0
[Skill]GitBook搭建
html prism.js 代码前端高亮、代码美化
* https://blog.csdn.net/qq_38504396/article/details/79835475 *
卓越笔记
2023/02/18
3.5K0
html prism.js 代码前端高亮、代码美化
Typecho文章代码高亮功能
Typecho是一款由国人开发的博客程序,它的特点是简洁小巧,扩展性强,并且内置支持Markdown语法写作,因而很受技术博客作者的欢迎。但是默认的Typecho没有自带语法高亮,要实现语法高亮就要使用Typecho相应的插件,而Typecho的插件安装和调试都比较难,这里就将介绍一种不使用插件来实现几乎所有语言的语法高亮的方法。
HCG_Sky
2020/07/24
3.7K0
Typecho文章代码高亮功能
使用 Prism.js 实现漂亮的代码语法高亮
给大家推荐一个代码高亮显示的东东,直接使用一个 JavaScript 库 —— Prism 是一款轻量、可扩展的代码语法高亮库,使用现代化的 Web 标准构建。 为什么选择 Prism.js ? 极致易用引用 prism.css 和 prism.js,使用合适的 HTML5 标签(code.language-xxxx),搞定!天生伶俐语言的 CSS 类是可继承的,所以你只需定义一次就能应用到多个代码片段。轻如鸿毛代码压缩后只有 1.6KB。每添加一个语言平均增加 0.3-0.5KB,主题在 1KB 左右
沈唁
2018/05/24
4.4K0
prism代码高亮主题风格展示阁
如何使用代码高亮插件,之前的教程中已经写过了,在这里我不再说明,接下来给大家展示下代码高亮插件所支持的主题风格有哪些以及各自的展示效果。
YangAir
2020/04/29
2.7K0
【Webpack】632- 了不起的 Webpack 构建流程学习
Webpack 是前端很火的打包工具,它本质上是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 Webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有模块打包成一个或多个 bundle。
pingan8787
2020/06/24
1K0
Markdown 写 PPT 是如何实现的?
Markdown 是一种轻量的标记语言,我们只需要写 md 格式文件,不必考虑文档的排版,被广泛用于博客写作,技术文档编写等,程序员们都热爱,但我们工作中除了写文档,有时候还需要汇报工作,技术分享等,需要用到 PPT,但设计 PPT 可能不是每个程序员所喜欢的,所以我们可以使用一个非常好用的工具 slidev, 可以使用 markdown 来制作演示文稿, 这个工具很多小伙伴都知道,尤大的分享就经常使用,其他类似的工具还有 Nodeppt、 marp 等,那么这类工具是如何实现的?
狂奔滴小马
2022/09/21
9890
Markdown 写 PPT 是如何实现的?
几分钟上线一个项目文档网站,这款开源神器实在太香了!
Docsify是一款开源的文档生成工具,目前在Github上已有21K+Star。Docsify可以快速帮你生成文档网站,不同于VuePrese和Hexo的地方是它不会生成静态的.html文件,所有转换工作都是在运行时。
macrozheng
2022/12/14
2K0
几分钟上线一个项目文档网站,这款开源神器实在太香了!
Prism:轻量级的 Javascript 代码高亮库
代码高亮的程序或者 WordPress 插件有很多,但是在碰到 Prism 之前,我爱水煮鱼都没有使用代码高亮的程序,就是因为以前的那些代码高亮的程序或者插件太臃肿或者复杂,使用起来不方便。那么 Prism 有哪些地方吸引了我呢?
Denis
2023/04/14
8760
Prism:轻量级的 Javascript 代码高亮库
MVC中局部刷新使用PRISM代码高亮
当你在局部刷新肯定是把html在通过ID定位覆盖,你只要把代码高亮的执行直接写在这个局部刷新的html下面即可
Shunnet
2022/06/29
6550
MVC中局部刷新使用PRISM代码高亮
基于prismjs的Typecho代码高亮插件CodeHighlighter
CodeHighlighter插件是一款基于prismjs的代码语法高亮typecho插件,支持众多常见的代码语言高亮显示,官方提供8种代码高亮风格自由切换,支持显示代码语言类型、行号,以及支持复制代码到剪切板功能。
小唐同学.
2022/02/18
1.8K0
基于docsify的基本操作&配置
​ 多级目录构建navbar、sidebar引用404问题:在构建多级文件目录的时候,针对多级文件夹下的md文件,其会相应加载同级目录下的navbar.md、sidebar.md文件,但这个时候由于navbar.md、sidebar.md文件存放在根目录或者是自定义指定的文件夹下,引用相对路径则会报404问题。针对上述情况,可以有如下调整方案:
hahah
2022/08/30
2.9K0
教你使用docsify生成美观的文档网站
docsify 是一个动态生成文档网站的工具,可以将.md 文件以 wiki 的形式展示给读者,可以用于制作技术文档、用户手册、wiki 等,快速以网站形式构建、发布软件的API手册或用户说明文档,方便用户使用你的软件,达到快速传播作用。可以部署于主机、VPS、Github、静态云存储(例如阿里云 OSS)。
Lcry
2022/11/29
1.4K0
教你使用docsify生成美观的文档网站
前端三大构建工具横评,谁是性能之王!
而在Vite之前,还有Snowpack也同样采用了No-Bundler构建方案。那么No-Bundler模式与传统老牌构建工具Webpack孰优孰劣呢?能否实现平滑迁移和完美取代?
zz_jesse
2021/03/26
1.3K0
前端三大构建工具横评,谁是性能之王!
Markdown 拓展-Docsify 构建接口文档
优点:使用 markdown 编写,docsify 作为支撑。快速高效,若搭载搜索功能,功能较为完善。且可部署在内网环境。
acc8226
2022/05/17
5060
Markdown 拓展-Docsify 构建接口文档
相关推荐
利用Prism.js脚本工具实现网页代码高亮效果
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验