要把前端和后端写在同一个文件里
假如我们需要设计一个需要密码才能登录的页面,某些偷懒的大聪明可以很容易地写出这样的代码:
1 | function login(password) { |
如果读者有一定的Web开发经验,一定能一眼看出这段代码很好地解释了什么叫掩耳盗铃。
当然,如果你还看不出,那么我们稍微提示一下
前端代码在浏览器中运行,用户可以很容易地拿到前端代码。
所以只需要稍微分析一下,就能直接获得正确的密码“fuck“,这种在前端进行验证的行为显然只有大聪明才能写出来。
那么,如果我们把验证部分放到后端进行呢?
好,你成功领悟到了前后端分离的核心思想,于是我们吭哧吭哧地搭了一个后台服务器,再吭哧吭哧地写API文档,最后吭哧吭哧地联调上线,最后在某个通宵的夜里,当所有功能正常通过测试,我们终于可以坐下来歇一口气:#&¥*@&#&¥*&%(@&#$$*#%@……
那么,我为什么不能直接在前端写后端的代码呢?
于是你得到了Remix。
……
哈哈,开个玩笑,Remix虽然部分实现了这么个操作,但我认为依然不够灵活,因此,我尝试了设计一个编译器/框架/库库(总之随便你怎么叫吧,我就叫编译器了),让开发者可以同时在一个文件里写前和后端代码,并在编译时分离出前端和后端代码,进行分别部署。
那么,它怎么用呢?
啊,实际上我还没写完,你问的太快了。
当然,在我写完之前,我觉得有必要整理一下当前的需求,并设计相应的语法出来。
1. 在注释中添加 @remux <名字> 标记该代码运行在哪个端上
也可以是别的什么关键字,总之目前先用remux
吧。
我们以上面的代码为例,进行如下修改
1 | // @remux server |
好,现在编译器就知道了,**login
函数在服务器上运行,下面那条语句只会在客户端上运行,在服务端上会被删除**。
于是我们发现了新的问题,客户端的函数怎么可能直接调用服务器上的函数呢?!所以接下来,我们需要使用RPC(Remote Process Call,远程过程调用)对非本端的函数进行封装。
2. 非本端的函数会封装成RPC
好吧,就算函数没问题了,但是变量怎么办呢?例如下面的代码
1 | // @remux server |
我们看到,经过编译后,aServerVar
这个变量的声明在客户端上会消失,这就导致接下来aServerVar += 1;
中的变量未声明而执行出错,我们不希望这种情况发生,因此我们给编译器设下第3条规则
3. 非本端的变量声明会被封装为Proxy并实现RPC
RPC真是太棒了,可是编译器并不关心开发者使用什么RPC方案,所以我们决定把RPC的具体实现留给开发者,编译器本身只负责封装
4. 与标记名关联的函数会被作为RPC客户端调用
具体来说呢,在客户端上,上面的login
函数会被封装成
1 | async function login(...args) { |
而对于变量声明,则会封装成
1 | let aServerVar = new Proxy( |
而对于被调用的端,存在编译器提供的函数用于接收调用
1 | // 这是编译器提供的!不需要开发者自己写 |
是不是很简单?所以开发者只需要实现一下xxxInvoke
函数,并写好相应的RPC服务(甚至可以直接在这个文件里写好),把参数一股脑传给yyyHandler
,然后返回到xxxInvoke
就完成啦,RPC从未如此简单。
也许对于一些没写过RPC的小白,这可能有一定困难,因此我们会尝试提供一个专为该编译器设计的RPC实现,以方便需要快速上手的玩家们。
当然,这也就意味着在server
端上,clientInvoke
和clientHandler
是完全没必要的,所以
5. 非本端的RPC函数会被删除
我们还希望所有端都能共用一些代码,例如某些类型的声明、公共的函数、公共的变量等,所以
6. 未标记的代码所有端上都会执行
但是有些代码我们压根就不希望被其他端调用,例如私有的函数或是变量,尽管可以在RPC层面做限制(RPC必须有限制,不然会产生任意执行漏洞),但是我们还是可以让编译器做一些处理,在此,我想出了两种方案
使用块语句,例如
1
2
3
4
5// @remux server
{
function aPrivateFunction () {}
let aPrivateVar = 1919810;
}这种方式的好处是不会破坏JavaScript语法,坏处是可能无法实现某些功能,例如在公共函数中调用私有函数或变量(当然反过来没问题,在私有语句中调用公共函数或变量)
使用额外的标记,例如
// @remux server private
声明私有的变量和函数,这样在其他端上会被抹去,而不是封装成RPC,但是这种做法会对语法造成一定的破坏,这是我不太希望看到的,尽管编译器可以对不正确的变量或函数使用进行警告或报错,但依然会对开发者在编写程序上造成一定的困惑
对于这个需求的实现方法我还在犹豫不决,因此,如果你有好的想法欢迎在下方留言处指点,或者直接与我交流,总之,在此保留第7条规则。