<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          你不知道的 WebIDE:5000字,剖析實現(xiàn)細節(jié)

          共 4353字,需瀏覽 9分鐘

           ·

          2020-11-02 16:27

          前言

          3年前在AWS re:Invent 大會上AWS?宣布推出?Cloud9, 用于在云端編寫、運行和調(diào)試代碼,它可以直接運行在瀏覽器中,也就是傳說中的?Web IDE。3年后的今天隨著國內(nèi)云計算的發(fā)展, 各大云計算服務廠商都在部署自己的WEB IDE, 而且已經(jīng)有非常成熟的落地方案, 對于這一塊的技術原理和實現(xiàn), 也非常值得我們?nèi)W習和剖析.

          目前比較成熟的WEB IDE方案有CodeSandbox,?Cloud Studio等, 接下來筆者將實現(xiàn)一個簡單的WEB IDE, 來帶大家了解其原理和實現(xiàn)過程.

          正文

          筆者接下來會介紹WEB IDE的實現(xiàn)原理和應用場景, 并介紹如何在H5-Dooring中使用它.

          1. web編輯器實現(xiàn)原理

          我們先來看看一個成熟WEB IDE的結構:

          抽象出來可以分為3個核心部分:

          • 文件導航區(qū)

          • 代碼編輯區(qū)

          • 預覽容器

          如下圖所示:

          在把模塊抽象出來之后我們來思考具體的功能實現(xiàn). 對于文件導航區(qū)我們可以很容易的使用react/vue的ui庫來實現(xiàn), 對于文件保存, 目錄樹生成等我們可以使用nodejs + DB(如mysql,Redis)來實現(xiàn). 代碼編輯區(qū)我們可以用第三方成熟的庫比如react-codemirror2?或者react-monaco-editor來做. 由于預覽容器我們不清楚預覽類型(如小程序,?web頁面還是app), 所以這里我們暫時考慮web頁面容器, 也就是我們比較熟悉的iframe. 那么我們可以畫出如下技術實現(xiàn)圖:

          實際上WEB IED實現(xiàn)過程遠比上面的復雜, 我們這里只做簡單的抽象. 我們接下來梳理一下在線代碼編輯器的需求:

          • 支持在線編寫前端代碼(html,javascript,css)
          • 支持實時預覽
          • 支持代碼在線下載

          1.1 技術選型

          在了解了以上實現(xiàn)方式之后, 我們開始來搭建環(huán)境并進行代碼開發(fā). 以下列舉我們的技術選型:

          • koa?基于nodejs的服務端框架
          • koa-static?基于koa的靜態(tài)資源中間件
          • koa-body?解析請求體的中間件
          • koa2-cors?處理跨域的中間件
          • koa-logger?處理請求日志的中間件
          • react?前端框架
          • react-codemirror2?代碼編輯器
          • antd?基于react的前端組件庫
          以下是筆者實現(xiàn)的效果圖:

          1.2 實現(xiàn)細節(jié)

          對于以上筆者列出的koa和react的技術方案不熟悉的大家可以先了解一下,筆者這里直接實現(xiàn)具體邏輯。

          我們先用umi來創(chuàng)建工程,然后在根目錄新建server.js文件。該文件主要用來處理nodejs相關邏輯,在稍后我會詳細介紹。

          界面的實現(xiàn)筆者不一一介紹了,前端模塊筆者來介紹一下如何配置代碼編輯器。react-codemirror2基本使用方式如下:

          import {UnControlled as CodeMirror} from 'react-codemirror2';
          require('codemirror/mode/xml/xml');
          require('codemirror/mode/javascript/javascript');

          export default function() {
          // ...
          return (
          className={styles.codeWrap}
          value={html}
          options={{
          mode: 'xml',
          theme: 'material',
          lineNumbers: true
          }}
          onChange={handleChange}
          cursor={cursor}
          onCursor={onCursorChange}
          />

          );
          }

          復制代碼

          通過以上方式我們就能生成一個基本的代碼編輯器,需要注意的是我們需要再單獨引入對應的主題樣式文件:

          @import '~codemirror/lib/codemirror.css';
          @import '~codemirror/theme/material.css';

          復制代碼

          為了實現(xiàn)預覽功能,筆者之前想了兩種方案,一種是直接通過頁面組件的方式來實現(xiàn)預覽,但是缺點是只有dom和樣式更新能生效,如果編寫js代碼,由于react的內(nèi)部機制是無法直接執(zhí)行script的。

          另一種方案是iframe,這種方案可以很好的隔離react和預覽代碼,實現(xiàn)機制如下

          也就是說我們在代碼編輯器里編輯完代碼之后統(tǒng)一通過請求的方式保存在node端,然后通過iframe請求nodejs渲染的靜態(tài)頁面來實現(xiàn)預覽功能。有點類似服務端渲染的感覺。

          那么如何保證實時預覽呢?這塊完全可以設計成用戶手動點擊預覽,也是筆者最初的設想,但是為了增強用戶體驗,筆者決定采用實時預覽, 也就是用戶代碼的變化可以實時反應在“預覽窗口”。方案就是在onChange中更新state來實現(xiàn)rerender,這一點用react hooks很好實現(xiàn)。但是實時更新對性能很不友好, 所以為了提高預覽性能和頁面體驗,筆者在這里使用防抖來控制請求頻次和時機。代碼如下:

          const handleChange = (editor, data, value) => {
          fetchPage(value)
          }
          const fetchPage = (v) => {
          if(timer) clearTimeout(timer);
          timer = setTimeout(() => {
          fetch('http://localhost:80/dooring/render', {method: 'POST', body: v}).then(res => {
          html = v
          setUpdate(prev => !prev)
          });
          }, 1000);
          }

          復制代碼

          在開發(fā)中還遇到同一個問題就是iframe每刷新一次,代碼編輯器的光標都會被重置,這一點對用戶在線coding的體驗非常不好,所以筆者又看了一遍官方文檔,找到了cursor這個有意思的api,中文的意思就是說可以手動設置光標停止的位置,那么我們在每次光標變化的時候都強制設置為當前光標所在的位置,那么就不會應為iframe刷新的影響而被迫觸發(fā)失焦動作了。代碼實現(xiàn)如下:

          const onCursorChange = (editor, data) => {
          const { line, ch } = data
          setCursor({ line, ch })
          }
          // ...
          className={styles.codeWrap}
          value={html}
          options={{
          mode: 'xml',
          theme: 'material',
          lineNumbers: true
          }}
          onChange={handleChange}
          cursor={cursor}
          onCursor={onCursorChange}
          />

          復制代碼
          至此我們的核心功能就實現(xiàn)了,如下圖:

          對于界面中的下載html功能以及一件部署的功能都比較簡單,筆者已將代碼提交到github,感興趣的可以學習了解一下。

          1.3 服務端實現(xiàn)

          服務端實現(xiàn)主要是寫請求接口來存儲html頁面以及直出html頁面,對于跨域請求我們還需要處理跨域問題, 由于代碼邏輯比較簡單, 這里筆者的實現(xiàn)代碼如下:

          // server.js
          const Koa = require('koa');
          const { resolve } = require('path');
          // const staticServer = require('koa-static');
          const koaBody = require('koa-body');
          const cors = require('koa2-cors');
          const logger = require('koa-logger');
          const fs = require('fs');

          const app = new Koa();
          app.use(koaBody());
          app.use(logger());

          // 設置跨域
          app.use(cors({
          origin: function (ctx) {
          if (ctx.url.indexOf('/dooring') > -1) {
          return '*'; // 允許來自所有域名請求
          }
          return '';
          },
          exposeHeaders: ['WWW-Authenticate', 'Server-Authorization', 'x-test-code'],
          maxAge: 5, // 該字段可選,用來指定本次預檢請求的有效期,單位為秒
          credentials: true,
          allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
          allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'x-requested-with', 'Content-Encoding'],
          }));

          let htmlStr = ''

          app.use(async (ctx, next) => {
          console.log(ctx.url);
          if(ctx.url === '/dooring/render') {
          htmlStr = ctx.request.body;
          ctx.body = 'success';
          }else if(ctx.url.indexOf('/html') === 0) {
          ctx.type = "html";
          ctx.body = htmlStr;
          }
          });

          app.listen(80);

          復制代碼

          2. 應用場景

          對于在線coding的應用場景,筆者大致舉幾個應用場景。比如說我們在H5-Dooring編輯器中,要實現(xiàn)用戶自定義組件庫或者自定義h5頁面,并實時下載預覽,我們可以直接使用它,如下:

          其次,對于需要部署和實時修改的網(wǎng)站,如果上線之后需要快速修改部署,我們可以直接在線coding之后一件部署。對于個人技術博客來說也是可以實現(xiàn)在線編輯和在線一鍵部署,這樣我們就無需依賴特定環(huán)境和特定電腦了。對于更多強大的應用,對于企業(yè)級來說,也可以實現(xiàn)在線coding的方式寫服務端代碼,在線寫sql。比如云開發(fā),云計算領域催生的在線saas協(xié)作等。

          3. 總結

          以上教程筆者的一個簡單版本,基本上可以實現(xiàn)在線寫前端代碼,對于一些更復雜的功能,通過合理的設計也是可以實現(xiàn)的,大家可以自行探索,筆者已將在線編寫H5頁面的代碼和邏輯集成到H5-Dooring項目里,大家可以自行下載學習。

          github地址:H5在線編輯器H5-Dooring


          ●?你不知道的 React Hooks(萬字長文,快速入門必備)

          ●?UmiJS 中后臺項目實踐

          ●?【效果高能】你不知道的 Animation 動畫技巧



          ·END·

          圖雀社區(qū)

          匯聚精彩的免費實戰(zhàn)教程



          關注公眾號回復 z 拉學習交流群


          喜歡本文,點個“在看”告訴我

          瀏覽 223
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  麻豆18禁在线看 | 77777亚洲 | 福利第一页 | 亚洲欧美日本一区二区三区 | 亚洲视频在线观看免费观看 |