在 Deno 上实现简单的React SSR

4,004 阅读2分钟

前言

Deno 1.0 已经 release,但是不稳定,目前很多标准库都是 to do 状态,生态有待完善。毕竟 Node.js 社区也是经过了数年才发展起来的。

但是一经 release 就火起来了,有如下优点~

  • 安全,启用网络、文件、环境入口需要执行命令进行声明
  • 支持开箱即用的 TypeScript
  • 自带代码格式化和依赖检查
  • 拥有 Deno自己的标准库 deno.land/std
  • 干掉了集中化的代码仓库,通过url和文件import

安装Deno

请移步到 Deno 官方的脚本,一条命令安装 Deno,记得按安装成功的提示配置环境变量哦~

引入依赖-URL引入与import_map

Deno有两种依赖引入方式:

  1. URL 直接引入
//import {所需的对象} from 'module地址'
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

assertEquals("hello", "hello");
assertEquals("world", "world");

console.log("Asserted! 🎉");

在执行的时候,如果没有该module的缓存,会先下载

$ deno run test.ts
Compile file:///mnt/f9/Projects/github.com/denoland/deno/docs/test.ts
Download https://deno.land/std/testing/asserts.ts
Download https://deno.land/std/fmt/colors.ts
Download https://deno.land/std/testing/diff.ts
Asserted! 🎉
  1. import_map 引入(目前不稳定) 可能这里,有同学没接触过import map。import map 是 JavaScript 的新提案。自行搜索查看哦(不是本文重点)~

在 Deno 使用 import map 有如下限制:

  • 单个 import map
  • 没有回调的 URLs
  • Deno 不支持 std: namespace
  • 只支持 file:, http: 和 https:
// import_map.json

{
   "imports": {
     "引入名/(备注一下,/是必须的)": "module地址"
      "http/": "https://deno.land/std/http/"
   }
}
// hello_server.ts
//import {对象} from "在import_map声明的名词/模块.ts"
import { serve } from "http/server.ts";

const body = new TextEncoder().encode("Hello World\n");
for await (const req of serve(":8000")) {
  req.respond({ body });
}

执行的时候一定要带上 --importmap=import_map.json --unstable ,否则deno不知道是使用 import map 引入依赖

$ deno run --allow-net --importmap=import_map.json --unstable hello_server.ts

类型声明

deno 不会自动去找 .d.ts 文件,需要在代码注释里面声明,没看错~就是在代码注释里面声明

// @deno-types="类型声明文件(可以本地引用,可以远程URL引用)"
// @deno-types="./foo.d.ts"
import * as foo from "./foo.js";

写React

一切准备就绪,可以开始写 React 了

App.tsx

// @deno-types="https://deno.land/x/types/react/v16.13.1/react.d.ts"
import React from 'https://dev.jspm.io/react'

export const App = () => <div>Hello YYDeno with React!</div>

服务端渲染和输出

跑起 React 还是得到浏览器去,这时候回到主旨->服务端渲染,利用 ReactDOMServer 将 React 在服务端渲染,之后使用 Deno Server进行输出。

Server.tsx

// Import maps写法,目前不稳定
import { serve } from "http/server.ts";
import React from 'https://dev.jspm.io/react'
// import { serve } from "https://deno.land/std@0.51.0/http/server.ts";
import ReactDOMServer from 'https://dev.jspm.io/react-dom/server'
import { App } from './App.tsx'

export const str = ReactDOMServer.renderToString(<App />);

const body = new TextEncoder().encode(str);
const s = serve(":8080");
window.onload = async () => {
  console.log("http://localhost:8080/");
  for await (const req of s) {
    req.respond({ body });
  }
};

执行与权限声明

到现在,我们还没有讨论过在 Deno 上如何编译 TS 和 TSX~

答案是不用编译, Deno 自带执行 TS 和 TSX 现在就让我们愉快地来执行一下刚刚写的 React SSR 。

对了 Deno 是安全的运行环境,所以需要用到的文件、网络、环境的操作,在执行的时候必须添加 flag 声明 --allow-net

执行命令:

deno run --allow-net Server.tsx

如果想用 Import maps依赖的形式,需要添加 flag 声明才能启动:

deno run --allow-net  --importmap=import_map.json --unstable  Server.tsx

总结

  • Deno 开箱即用的 Typescript 和 TSX 环境对于使用 Typescript 开发来说方便了许多。
  • Deno 在启动命令中使用 flag 声明操作,一定程度上提高了安全性。起码第三方库不会乱操作本地文件,网络等等。
  • 引用第三方库很爽,写个地址就可以 ,像极了 Go、 Rust 的包管理。
  • Deno 自带的标准库很丰富,尽管现在还不完善。
  • 本例子代码