博客
关于我
如何制作一款在线编译器
阅读量:407 次
发布时间:2019-03-05

本文共 2948 字,大约阅读时间需要 9 分钟。

在文章开始之前先展示一下我自己做的在线编译器 JS-Encoder:

大概三四个月之前我开始有了制作在线编译器的想法。在此之前我接触过很多在线编译器,如 CodePen 和 JsBin 等,这些都非常优秀且有着庞大的用户群体。在线编译器支持很多种语言、代码变色、诸多快捷键以及个性化设置,使得它们看起来和本地下载的编译器软件几乎无异。我完全不知道这些复杂功能要怎么实现,因此我观察了 CodePen 和 JsBin 的代码,发现它们都使用了一个叫 codemirror 的工具。

codemirror 是一个用于浏览器的 JavaScript 实现的多功能文本编辑器。它专门用于编辑代码,并带有许多语言模式和插件,能够实现更高级的编辑功能。原来这些编译器都是依靠 codemirror 来实现的,而 codemirror 本身采用直接操作 DOM 的方式。不过我的项目是使用 Vue + Webpack 构建的,这违背了 Vue 的数据驱动宗旨。于是,我在 npm 上找到了一个采用 Vue 的方式构建代码编辑器的工具。

codemirror 有很多配置项,我在自己的项目中使用了如下配置。如果你想查看全部配置,可以看以下代码:

cmOptions: {flattenSpans: false,tabSize: 2,mode: '',theme: 'monokai',smartIndent: true,lineNumbers: true,matchBrackets: true,lineWiseCopyCut: true,indentWithTabs: true,electricChars: true,indentUnit: 2,autoCloseTags: true,autoCloseBrackets: true,foldGutter: true,cursorHeight: 1,keyMap: 'sublime',extraKeys: {'Ctrl-Alt': 'autocomplete','Ctrl-Q': cm => { cm.foldCode(cm.getCursor()) }},gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],styleActiveLine: true}

这些配置只是其中一部分,但足够实现我想要的功能了。mode 表示当前编辑器使用的语言,theme 表示编辑器使用的配色。官方支持很多种配色,但没有配色预览,所以我直接使用了 monokai 作为主题,因为我比较喜欢 vscode 的配色。于是,我找到 monokai.css 文件并修改了许多样式,虽然最终还是和真正的 vscode 主题有差异,但我真的尽力了😭。

keyMap 我设置为 sublime,sublime 上大部分快捷键都是可用的。其他配置我在注释里应该已经说明白了,这里就不详细解释了。codemirror 的效果还是不错的。

有了 codemirror 这个神器,可以说最难的问题已经解决了,但还有很多数不清的小问题需要解决。

布局方面我参考了 JsBin 的布局,因为我觉得它的界面看起来很简洁舒服。JsBin 的布局是这样的:分为五个窗口,鼠标放到两个窗口的边界上可以拖动改变窗口大小。鼠标的拖动会使得一个窗口宽度增加,而另一个窗口宽度减少,但两个窗口宽度之和是不会改变的。

我的思路是:在点击边界的时候获取两个相邻窗口的宽度,鼠标拖动的时候计算鼠标水平移动距离,并对两个窗口的宽度进行相应增减。由于这五个窗口都是同级的子组件,一个窗口获取另一个窗口的宽度比较麻烦,所以我将这五个窗口的宽度都放在 VueX 中储存以便使用,每一个窗口的宽度都随着 VueX 中宽度信息的改变而改变。

成功实现了效果:为了避免两个窗口重合问题,我设置了 min-width: 100px 的样式。除了两个窗口的问题之外,还要做到所有窗口宽度随着浏览器宽度变化而改变。这个效果也很容易实现,只要在浏览器宽度改变的时候每个窗口的宽度加上或减去改变宽度/窗口数量就可以了。

这是我第一次真正接触 iframe 这个东西,可能他很简单,但我确实在它身上花了不小的力气。解决了窗口拖动的问题,但这对 iframe 是无效的,我一直很困惑,找不出原因,最后突然想到 iframe 是一个独立的新页面,在 iframe 之外触发的事件不会影响到 iframe 本身。当我用鼠标拖动边界的时候,如果鼠标进入了 iframe 中,那么这个拖动事件就失效了。所以在拖动时需要给 iframe 外面加一个透明的遮罩层,这样就不会出现拖不动的问题了。

在用户一段时间内不输入任何字符或者用户直接点击运行按钮的时候,需要将编辑器中的 HTML、CSS 和 JavaScript 代码放到 iframe 中,iframe 就会将最终效果展示出来。编辑器中的内容也会放在 VueX 中。

codemirror 可以实现很多功能,但编译这件事儿他是不干的。像 JsBin 和 CodePen 这样的编译器不仅支持普通的 HTML、CSS 和 JavaScript 还支持很多这三种语言的预处理语言。比如我选择了 TypeScript 作为预处理语言,那么编译器就需要先将 TypeScript 转化为 JavaScript 再传给 iframe。

由于 JS-Encoder 是一个完全没有后台的编译器,所以要引入其他预处理语言的 npm 包和文件来编译。比如在实现 Sass 和 Scss 的编译上,我引入了 Sass.js 和 Sass.worker.js 来编译:

async function compileSass(code) {if (!loadFiles.get('sass')) {const Sass = await require('./sass')Sass.setWorkerUrl('static/js/sass.worker.js')loadFiles.set('sass', Sass)}const defSass = loadFiles.get('sass')const sass = new defSass()return new Promise((resolve, reject) => {sass.compile(code, result => {if (result.status === 0) resolve(result.text)else reject(new Error('fail to get result'))})})}

这里 loadFiles 只是用于判断是否已经引入过这些文件而已。我是在上看到这个编译方法的。

目前 JS-Encoder 从正式开发到现在已经有两个月,因为学业原因也没有过多的时间投入到开发中。目前 JS-Encoder 还是一个半成品,除了一些基本的之外其实还有很多功能没有或者正在实现。如果感兴趣的话可以在github上关注这个。随着更多功能的实现,我会继续更新这篇文章。

转载地址:http://ygqzz.baihongyu.com/

你可能感兴趣的文章
NIO蔚来 面试——IP地址你了解多少?
查看>>
NISP一级,NISP二级报考说明,零基础入门到精通,收藏这篇就够了
查看>>
NISP国家信息安全水平考试,收藏这一篇就够了
查看>>
NIS服务器的配置过程
查看>>
Nitrux 3.8 发布!性能全面提升,带来非凡体验
查看>>
NiuShop开源商城系统 SQL注入漏洞复现
查看>>
NI笔试——大数加法
查看>>
NLog 自定义字段 写入 oracle
查看>>
NLog类库使用探索——详解配置
查看>>
NLP 基于kashgari和BERT实现中文命名实体识别(NER)
查看>>
NLP 模型中的偏差和公平性检测
查看>>
Vue3.0 性能提升主要是通过哪几方面体现的?
查看>>
NLP 项目:维基百科文章爬虫和分类【01】 - 语料库阅读器
查看>>
NLP_什么是统计语言模型_条件概率的链式法则_n元统计语言模型_马尔科夫链_数据稀疏(出现了词库中没有的词)_统计语言模型的平滑策略---人工智能工作笔记0035
查看>>
NLP三大特征抽取器:CNN、RNN与Transformer全面解析
查看>>
NLP学习笔记:使用 Python 进行NLTK
查看>>
NLP度量指标BELU真的完美么?
查看>>
NLP的不同研究领域和最新发展的概述
查看>>
NLP的神经网络训练的新模式
查看>>
NLP采用Bert进行简单文本情感分类
查看>>