如何制作一款在线编译器

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

点此预览

大概三四个月之前我开始有了制作在线编译器的想法,在此之前我接触过很多的在线编译器,如CodePenJsBinJsFiddle等,这些都非常优秀且有着庞大的用户群体的编译器。

我一直对在线编译器的实现抱有浓厚兴趣,这些在线编译器支持很多种语言,代码变色,诸多的快捷键以及一些个性化设置,这使得在线编译器看上去和我们在本地下载的编译器软件也不会有太大的区别,我完全不知道这些复杂的功能要怎么实现,于是我观察 CodePenJsBin 代码发现他俩都使用了一个叫 codemirror 的工具。

codemirror

codemirror 是一个用于浏览器的 JavaScript 实现的多功能文本编辑器。它专门用于编辑代码,并带有许多语言模式和插件 ,可实现更高级的编辑功能。

原来这些编译器是依靠 codemirror 来实现的,codemirror 是一个非常复杂的工具,以至于我花了两天时间才熟悉它的配置项。codemirror 本身是采用直接操作 DOM 的方式,而我的项目是使用 Vue + Webpack 构建的,这违反了 Vue 数据驱动 的宗旨,于是我在 npm 上发现了 vue-codemirror 这个工具,采用 Vue 的方式构建代码编辑器

codemirror 有许多配置项,我在自己的项目中用到了如下配置,如果你想看全部配置,可以看这里

cmOptions: {
        // codemirror config
        flattenSpans: false, // 默认情况下,CodeMirror会将使用相同class的两个span合并成一个。通过设置此项为false禁用此功能
        tabSize: 2, // tab缩进空格数
        mode: '', // 模式
        theme: 'monokai', // 主题
        smartIndent: true, // 是否智能缩进
        lineNumbers: true, // 显示行号
        matchBrackets: true, // 匹配符号
        lineWiseCopyCut: true, // 如果在复制或剪切时没有选择文本,那么就会自动操作光标所在的整行
        indentWithTabs: true, // 在缩进时,是否需要把 n*tab宽度个空格替换成n个tab字符
        electricChars: true, // 在输入可能改变当前的缩进时,是否重新缩进
        indentUnit: 2, // 缩进单位,默认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'], // 用来添加额外的gutter
        styleActiveLine: true // 激活当前行样式
      },

这些配置只是一小部分,但足够实现我想要的功能了

mode 表示当前编辑器使用的语言

theme 表示编辑器使用的配色,官方支持很多种配色,但确没有配色预览,所以我直接使用我熟悉的 monokai 作为主题,因为我比较喜欢 vscode 的配色,所以我找到 monokai.css 文件并修改了许多样式,虽然最后还是和真正的 vscode 主题有差异,但我真的尽力了??

keymap 我设置为 sublimesublime上大部分快捷键都是可用的

其他的配置我在注释里应该已经说明白了,这里就不解释了

codemirror 的效果还是不错的

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

布局

布局方面有很多是参考 JsBin 的,因为我觉得它的界面看起来很简洁,舒服

JsBin 的布局是酱婶儿的:

分为五个窗口,鼠标放到两个窗口的边界上可以拖动改变窗口大小

鼠标的拖动会使得一个窗口宽度增加,而另一个窗口宽度减少,但是两个窗口宽度之和是不会改变的

我的思路是:

在点击边界的时候获取两个相邻窗口的宽度,鼠标拖动的时候计算鼠标水平移动距离,并对两个窗口的宽度进行相应增减

由于这五个窗口都是同级的子组件,一个窗口获取另外一个窗口的宽度比较麻烦,于是我将这五个窗口的宽度都放在 Vuex 中储存以便使用,每一个窗口的宽度都随着 Vuex 中宽度信息的改变而改变

成功实现效果:

为了避免两个窗口重合问题,我设置了 min-width: 100px; 的样式

除了两个窗口的问题之外,还要做到所有窗口宽度随着浏览器宽度变化而改变:

这个效果也很容易实现,只要在浏览器宽度改变的时候每个窗口的宽度加上或减去 改变宽度/窗口数量 就可以了

Iframe

这是我第一次真正接触 iframe 这个东西,可能他很简单,但我确实在它身上花了不小的力气

我已经解决了窗口拖动的问题,但这对 iframe 是无效的,我一直很困惑,找不出原因,最后突然想到:

iframe 是一个独立的新页面,在 iframe 之外触发的事件不会影响到 iframe 本身,当我用鼠标拖动边界的时候,如果鼠标进入了 iframe 中,那么这个拖动事件就失效了,所以在拖动时候需要先给 iframe 上面加一个透明的遮罩层,这样就不会出现拖不动的问题了

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

编译

codemirror 可以实现很多功能,但编译这件事儿他是不干的,像 JsBinCodePen 这样的编译器不只是支持普通的 HTMLCSSJavaScript 而已,他们还支持很多这三种语言的预处理语言

比如我选择了 TypeScript 作为预处理语言,那么编译器就需要先将 TypeScript 转化为 JavaScript 再传给 iframe

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

async function compileSass(code) {
  // scss&sass
  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 支持MarkDownSassScssLessStylusTypeScriptCoffeeScript, 之后会考虑支持 LiveScriptJSX(React)

设置

JS-Encoder 中除了预处理语言的选择之外,还有以下设置

  • 延迟执行时间

    • 每一个可编辑窗口我都设置了 watch 监听值的变化, 频繁的输入会导致方法的频繁触发,所以我设置了防抖函数,在设置的延迟时间内用户没有输入任何字符,才会执行代码
  • 将和tab等宽度的space转化为tab
  • CDN
    • 可以添加外部的 CDN,这样会在执行 JavaScript 之前先引入 CDN
  • CSS
    • 可以添加外部的 CSS,这样会在执行 CSS 之前先通过 link 引入

总结

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

原文地址:https://www.cnblogs.com/FrankLongger/p/11223796.html

时间: 2024-07-31 09:19:39

如何制作一款在线编译器的相关文章

使用 CSS & jQuery 制作一款漂亮的多彩时钟

大家可能见过各种各样的时钟效果,比如多年前非常流行的 Flash 制作的各种新奇的动画时钟,现在的 Web 开发者们又开始应用 CSS3 和 Canvas 等最新技术来实现.而今天这里要分享的这款漂亮的多彩时钟效果大家不一定见过,赶紧来看看. 您可能感兴趣的相关文章 Web 开发中很实用的10个效果[附源码下载] 精心挑选的优秀jQuery Ajax分页插件和教程 12款经典的白富美型 jQuery 图片轮播插件 让网站动起来!12款优秀的 jQuery 动画插件 精心挑选的美轮美奂的 jQue

开发者、设计师和管理人员必备的20款在线工具(上)

当互联网越来越靠近我们生活的时候,网络技术的发展也使得我们更多的任务可以在网络上完成,比如设计和开发.今天小编给大家推荐20款不需要安装,借助浏览器即可完成项目的网页开发工具~ Animatron Animatron是一个与动画有关的在线工具,可以帮助你轻松制作HTML5和SVG动画,无需编写代码,可提高网站的体验和设计感. 目前Animatron提供不同层级的服务,从免费到20美元包月.可以将你从制作往网站动画效果的压力中释放出来,还可以帮助你将工作内容存储到云端,方便团队协作,一旦完成作品还

【app制作指南】如何制作一款属于自己的APP(移动客户端)?

大家都清楚制作app,都需要技术的,就这点技术会吓退很多想制作app的朋友们.我没技术,我也只能心有余而力不足啊.所以我今天给大家分享的是app制作指南,如果制作一款属于自己的APP(移动客户端). 其实,目前个人制作APP的方法有三种,一是合作开发,二是花钱找人开发,三是使用在线制作工具.本文将从这三个方面来一一介绍.  一.合作开发 合作开发是类似于资源互换方式,一方提供技术开发APP,而另一方则提供相应的资源,可以和一些团队合作开发APP,对于知名站点,一般都能免费帮助其开发,并与其资源互

[原创开源项目]EPUBBuilder一款在线的epub电子书编辑工具

epub 感觉自己么么哒, epub书:国外最流行的电子书格式: epub电子书介绍: epub全称为Electronic Publication的缩写,意为:电子出版, epub于2007年9月成为国际数位出版论坛(IDPF)的正式标准,以取代旧的开放Open eBook电子书标准,epub这种格式kindel目前不支持, 必须用相应的软件打开,比如PC端用calibre, firefox的插件EPUBReader , chrome的插件Readium 等: 网络上也有EPUB书籍比较好的编辑

cocos2d-x之道~制作第一款文字游戏(二)

在 cocos2d-x之道~制作第一款文字游戏(一)中,使用cocos2d-x把主界面显示出来,分别有每个级别提供的初始短语TileView,和目标短语TargetView.初步接触了cocos2d-x的基本概念和基础用法.这篇博客将会基本实现游戏的逻辑,完成游戏的主体部分.采用以下步骤: 使TileView可拖动 捕获TileView停止移动的事件 分析TileView是否放在正确的位置上 创建与原来Layer区分的层,放置按钮.菜单和分数等等. 添加计时和分数 现在开始,继续cocos2d-

如何制作一款HTML5 RPG游戏引擎——第三篇,利用幕布切换场景

开言: 在RPG游戏中,如果有地图切换的地方,通常就会使用幕布效果.所谓的幕布其实就是将两个矩形合拢,直到把屏幕遮住,然后再展开直到两个矩形全部移出屏幕. 为了大家做游戏方便,于是我给这个引擎加了这么一个类. 本系列文章目录: 如何制作一款HTML5 RPG游戏引擎--第一篇,地图类的实现 http://blog.csdn.net/yorhomwang/article/details/8892305 如何制作一款HTML5 RPG游戏引擎--第二篇,烟雨+飞雪效果 http://blog.csd

如何制作一款HTML5 RPG游戏引擎——第四篇,情景对话

今天我们来实现情景对话.这是一个重要的功能,没有它,游戏将变得索然无味.所以我们不得不来完成它. 但是要知道,使用对话可不是一件简单的事,因为它内部的东西很多,比如说人物头像,人物名称,对话内容... 因此我们只能通过数组+JSON来将对话信息装起来,然后根据信息作出不同的显示.接下来我便要向大家展示实现方法. 先看本系列文章目录: 如何制作一款HTML5 RPG游戏引擎--第一篇,地图类的实现 http://blog.csdn.net/yorhomwang/article/details/88

百度LBS开放平台个性化地图 制作一款独一无二的地图

百度LBS开放平台个性化地图  制作一款独一无二的地图 天天用百度地图的亲们是否已不再满足只看如下的地图样式了呢? 默认百度地图样式 是否特别渴望看特别不一样的地图呢,如带京城81号气息的午夜蓝风格.绿灯侠风格的青春绿地图及红色警戒风格的地图? 午夜蓝地图风格 青春绿风格地图 警戒红地图风格 如果你以为上述酷炫的地图只是PS出来的,那么你就out了,因为百度LBS开放平台已经对广大的开发者提供了定制如上个性化样式的地图功能啦~ 开发者可以从http://developer.baidu.com/m

如何制作一款HTML5 RPG游戏引擎——第五篇,人物&人物特效

上一次,我们实现了对话类,今天就来做一个游戏中必不可少的--人物类. 当然,你完全是可以自己写一个人物类,但是为了方便起见,还是决定把人物类封装到这个引擎里. 为了使这个类更有意义,我还给人物类加了几个特效,在以下讲解中会提到. 以下是本系列文章的目录: 如何制作一款HTML5 RPG游戏引擎--第一篇,地图类的实现 http://blog.csdn.net/yorhomwang/article/details/8892305 如何制作一款HTML5 RPG游戏引擎--第二篇,烟雨+飞雪效果 h