成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

前端實現(xiàn)多文件編譯器

原創(chuàng) 精選
開發(fā) 前端
一個前端可執(zhí)行的小型打包工具就已實現(xiàn),可以直接在前端進(jìn)行多文件的編輯和執(zhí)行。實時上,此過程僅適用于不方便借助服務(wù)器的場景,如果有條件允許可以借助服務(wù)器,那么編譯過程最好在服務(wù)端完成,甚至還可以借助 webpack 或 rollup 等打包工具實現(xiàn)更好的編譯效果。

作者 | 景遇

一、概要

在前端工程中,有時我們需要在瀏覽器編譯并執(zhí)行一些代碼,這種需求常見于低代碼場景中。例如我們在搭建時需自定義一部分代碼,這些代碼需要在渲染時執(zhí)行。為了方便起見,我們寫的代碼一定是 ES6 語法,如果要在瀏覽器執(zhí)行,那么就必須經(jīng)過編譯。下面是前端編譯 JS 代碼的一些實踐。

二、需求描述

  1. 低碼搭建時需要自定義一部分代碼
  2. 希望代碼是以多文件形式組織的
  3. 可以使用 ESModule 形式導(dǎo)入/導(dǎo)出

三、需求分析

  1. 在瀏覽器編譯代碼必然需要使用 babel 完成;
  2. 如果只有一個 JS 文件,那么可以直接使用 babel 的 transform 函數(shù)編譯
  3. 如果存在多文件,則文件內(nèi)的變量必須相互隔離,且文件之間能夠通過某種形式相互引用,并且需要考慮文件之間的依賴關(guān)

四、核心設(shè)計

流程

1.變量隔離

由于我們的需求是多文件編輯,各個文件內(nèi)的變量應(yīng)該相互隔離。最簡單的辦法是將每個文的內(nèi)容轉(zhuǎn)成一個閉包,再通過固定的接口將每個文件連接起來。

假設(shè)有 a.js,內(nèi)容如下:

const a = 1;
const b = 2;

function sum () {
return a + b'
}

sum();

可以將其轉(zhuǎn)為如下形式:

(function() {
const a = 1;
const b = 2;

function sum () {
return a + b'
}

sum();
})();

轉(zhuǎn)成這種形式之后,每個文件內(nèi)的變量就只會存在于各自的閉包之內(nèi),互不影響。

五、文件引用

文件之間的相互引用可以通過定義一種接口規(guī)則實現(xiàn):

  • 所有文件的引用都將通過全局變量 module 進(jìn)行
  • 每個文件都將對應(yīng)到 module 上的一個對象,key 根據(jù)文件名而定。

1.導(dǎo)出

原文件:

https://back-media.51cto.com/editor/h6e90be6-D8rA67LO

編譯后:

(function() {
__filename = 'a.js';
const a = 1;
var mod = {};
mod.a = a;
module[__filename] = mod;
})()

2.導(dǎo)入

源文件:

// b.js
import { hello } from './a'

hello();

編譯后:

(function() {
__filename = 'b.js';
var $$a = module['a.js'];
$$a.hello();
var mod = {};
module[__filename] = mod;
})()

六、依賴樹解析

假設(shè)有一堆文件,我們通過解析(babel 或正則)后得到他們之間的關(guān)系如下:

他們之間存在循環(huán)依賴。

根據(jù)這個依賴圖可以梳理出幾條依賴路線:

  • A -> B -> D -> C -> F -> 循環(huán)依賴B
  • A -> B -> E -> F -> 循環(huán)依賴 B
  • A -> C -> F -> B -> E -> 循環(huán)依賴 F
  • A -> C -> G

從開始出現(xiàn)的第一個循環(huán)依賴截斷依賴路線,分別統(tǒng)計統(tǒng)計每個節(jié)點的深度,按深度依次放入隊列中。

如果兩個節(jié)點深度相同,則分析兩個節(jié)點的依賴關(guān)系,被依賴的先進(jìn)隊列,故最終形成的隊列如下:

  • F E B C D G A

為什么要得到一個編譯順序呢?

以上得出的編譯順序是為了盡可能解決如下的引用情況,但也不能解決所有:

// a.js
export const a = 2

// b.js
import { a } from 'a.js';
console.log(a + 2);

這時候,假設(shè)執(zhí)行 b 的時候,a 還沒被執(zhí)行,那么 b 內(nèi)部拿到的 a 實際上是 undefined,顯然不是我們所希望的。所以此時必須保證 a 先于 b 執(zhí)行。

但這種使用方式在存在循環(huán)引用時無法解決,只能調(diào)整文件組織形式。

事實上,假設(shè)存在循環(huán)依賴時,下面的在函數(shù)內(nèi)或在類內(nèi)引用方式是沒有問題的,有問題的只是直接使用:

// a.js
export const a = 2

// b.js
import { a } from 'a.js';
export function test () {
return a + 1;
}

這樣,即使 b 有依賴 a,test 只要不是立即執(zhí)行函數(shù)也不會產(chǎn)生影響。

七、編譯

1.ESModule 轉(zhuǎn)換

此過程可以通過自定義一個 Babel 插件完成,在語法編譯時將文件編譯成一個閉包,同時處理好 ESModule 語法。

該 Babel 插件很簡單,在此就不展開去寫了。

2.文件隊列編譯

對單個文件的編譯可封裝成一個方法,假設(shè)函數(shù)名為:compileFile。

按照上面解析到的文件隊列按照順序逐個調(diào)用 compileFile 進(jìn)行編譯,并將結(jié)果直接拼接起來,形成一個巨大的字符串,該字符串的樣子應(yīng)該是如下的格式:

(function() {
__filename = 'b.js';
var $$a = module['a.js'];
// ...
var mod = {};
module[__filename] = mod;
})();

(function() {
__filename = 'a.js';
var $$b = module['b.js'];
// ...
var mod = {};
module[__filename] = mod;
})();

// ...

3.JS 執(zhí)行

最后一步,執(zhí)行上面得到的編譯結(jié)果即可,此步驟可直接使用 new Function 的方式完成,例如:

(假設(shè)以上的字符串內(nèi)容保存在 compiledScript 中)。

const exec = new Functioon(`
var module = {};
${compiledScript};
return module;
`);

const module = exec();

module['a.js'] // a.js 的導(dǎo)出內(nèi)容
module['b.js'] // b.js 的導(dǎo)出內(nèi)容

八、總結(jié)

至此,一個前端可執(zhí)行的小型打包工具就已實現(xiàn),可以直接在前端進(jìn)行多文件的編輯和執(zhí)行。

實時上,此過程僅適用于不方便借助服務(wù)器的場景,如果有條件允許可以借助服務(wù)器,那么編譯過程最好在服務(wù)端完成,甚至還可以借助 webpack 或 rollup 等打包工具實現(xiàn)更好的編譯效果。

參考

目前我們在 ali-lowcode-engine 之上的源碼插件(@ali/lowcode-plugin-code-editor)內(nèi)部實現(xiàn)了多文件的支持,目前僅做了最簡單的實現(xiàn):模塊引用直接采用了 UMD 規(guī)范,暫時也沒有考慮循環(huán)依賴和執(zhí)行順序。

后續(xù)會嚴(yán)格按照以上步驟進(jìn)行優(yōu)化。

責(zé)任編輯:武曉燕 來源: 阿里開發(fā)者
相關(guān)推薦

2022-11-24 13:05:27

ClangiOS

2010-01-27 16:39:48

C++編譯器

2016-11-08 18:53:08

編譯器

2021-06-08 07:48:26

lambda表達(dá)式編譯器

2021-06-25 10:38:05

JavaScript編譯器前端開發(fā)

2025-01-03 11:43:53

2010-01-18 10:34:21

C++編譯器

2010-01-21 09:11:38

C++編譯器

2009-08-10 17:12:54

C#編譯器

2017-03-20 18:01:55

編譯器匯編

2013-03-29 10:02:37

編譯器語言編譯開發(fā)

2010-01-22 18:33:17

C++編譯器

2010-03-23 11:17:16

Python 動態(tài)編譯

2010-10-20 13:43:37

C++編譯器

2019-08-06 08:20:07

編譯器工具開發(fā)者

2010-01-13 13:42:55

C++編譯器

2020-04-02 15:39:51

代碼編譯器前端

2015-03-23 10:04:43

c++編譯器c++實現(xiàn)原理總結(jié)

2010-02-02 17:08:26

Python靜態(tài)編譯器

2010-03-02 10:55:47

Linux SkyEy
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲精品一区二区冲田杏梨 | 亚洲一区在线播放 | 免费久久精品视频 | 九九视频网 | 国产精品久久久久久久久久 | 国产高清一区二区三区 | 成人国产精品久久久 | 青娱乐国产| 中文字幕av一区 | 国产精品国产三级国产aⅴ中文 | 国产精品一区二区精品 | 亚洲欧美一区二区三区1000 | 久久一视频 | 亚洲欧美精品国产一级在线 | 91综合网 | 免费高清av | 国产免费一区二区三区 | 欧美中文字幕在线 | 国产精品久久久久久久久久久免费看 | 亚洲欧美日韩在线不卡 | 玖玖综合网 | 亚洲女人天堂成人av在线 | 亚洲福利 | 成人欧美一区二区三区白人 | 91在线一区二区 | 色橹橹欧美在线观看视频高清 | 久久69精品久久久久久久电影好 | 日韩欧美视频免费在线观看 | 性在线 | 日韩有码一区 | 国产99在线 | 欧美 | av香港经典三级级 在线 | 久久曰视频 | 日本久久黄色 | 国产一区欧美一区 | 在线欧美一区 | 亚洲自拍偷拍免费视频 | 亚洲福利在线观看 | 久久精品这里 | 51ⅴ精品国产91久久久久久 | 欧美日韩国产在线观看 |