deno使用rust_使用graphql和deno构建ssr react应用程序

deno使用rust

介绍(Introduction)

Unless you have been living under a rock, I am sure you have been hearing all the hype on Deno and/or GraphQL in the past few years. If you are intrigued by these technologies and enjoy learning new technologies by building with them, then you're in the right place!

除非您一直生活在一块石头下,否则我相信您会在过去几年中听到有关Deno和/或GraphQL的所有炒作。 如果您对这些技术感兴趣,并且喜欢通过与它们一起构建来学习新技术,那么您来对地方了!

迪诺背景 (Background on Deno)

On May 13, 2018, Ryan Dahl, the creator of Node.js announced Deno, a new secure runtime for JavaScript and Typescript, during his “10 Things I Regret About Node.js” talk. In this talk, he mentioned some of the improvements that Deno aims to implement, such as abstracting the need for dependency solutions like NPM modules and package.json, supporting TypeScript out of the box by implementing a snapshotted TypeScript compiler, and breaking the sandboxed environment of the V8 engine.

2018年5月13日,Node.js的创建者Ryan Dahl在“我对Node.js的十件事感到遗憾”演讲中宣布了Deno,这是一个用于JavaScript和Typescript的新安全运行时。 在本次演讲中,他提到了Deno旨在实现的一些改进,例如抽象出对依赖解决方案(如NPM模块和package.json)的需求,通过实现快照TypeScript编译器开箱即用地支持TypeScript,以及打破沙盒环境。 V8引擎。

After two years, on May 13, 2020, it was announced that Deno was ready for production, and has been backed my major cloud providers such as AWS Lambda, Azure Functions, and Google Cloud Run.

两年后,即2020年5月13日,宣布Deno可以投入生产,并得到了我的主要云提供商的支持,例如AWS Lambda,Azure Functions和Google Cloud Run。

总览 (Overview)

Throughout this article, we will be building a simple application to show Rick and Morty character information utilizing React, GraphQL, and Deno. During the process, we will be implementing server-side rendering with Deno’s Oak framework, as well as executing and caching GraphQL queries with Deno’s Obsidian library.

在整个本文中,我们将构建一个简单的应用程序,以利用React,GraphQL和Deno显示Rick和Morty的角色信息。 在此过程中,我们将使用Deno的Oak框架实现服务器端渲染,并使用Deno的Obsidian库执行和缓存GraphQL查询。

让我们开始吧! (Let's get right into it!)

First things first, we need to set up our file structure.

首先,我们需要设置文件结构。

my-app
├── client
│ ├── Components
| ├── static
│ ├── app.tsx
│ └── client.tsx
├── server.tsx
├── deps.ts
├── serverDeps.tsx
├── staticFileMiddleware.ts
├── tsconfig.json
└── README.md
  • client is where we will store all our React components, static files, and theapp.tsx andclient.tsx files.

    client是我们存储所有React组件,静态文件以及app.tsxclient.tsx文件的地方。

  • deps.ts and serverDeps.ts serve to import all of the Deno modules used throughout the application in one place.

    deps.tsserverDeps.ts用于将整个应用程序中使用的所有serverDeps.ts模块集中到一个位置。

  • staticFileMiddleware.ts will contain the logic to handle requests for static files.

    staticFileMiddleware.ts将包含处理静态文件请求的逻辑。

  • tsconfig.json specifies the root files and the compiler options required to compile the TypeScript project.

    tsconfig.json指定根文件和编译TypeScript项目所需的编译器选项。

导入Deno模块 (Importing Deno Modules)

Since we have determined all of the libraries that we will be importing on our client-side and server-side, we will begin by creating deps.ts files to import them into our application.

由于我们已经确定了要在客户端和服务器端导入的所有库,因此我们将首先创建deps.ts文件以将其导入到我们的应用程序中。

import React from 'https://dev.jspm.io/react@16.13.1';
import ReactDom from 'https://dev.jspm.io/react-dom@16.13.1';
import {
  ObsidianWrapper,
  useObsidian,
} from 'https://deno.land/x/obsidian@v0.1.6/ObsidianWrapper/ObsidianWrapper.jsx';


export { React, ReactDom, ObsidianWrapper, useObsidian };
  • deps.ts is where we will be importing all the Deno modules that will be utilized in the client-side of the application.

    deps.ts是我们将导入将在应用程序客户端使用的所有Deno模块的地方。

import {
  Application,
  Router,
  Context,
  send,
} from 'https://deno.land/x/oak@v6.0.1/mod.ts';
import ReactDomServer from 'https://dev.jspm.io/react-dom@16.13.1/server';


export { Application, Router, ReactDomServer, Context, send };
  • serverDeps.ts is where we will be importing all the Deno modules that will be utilized in the server-side of the application.

    serverDeps.ts中,我们将导入将在应用程序服务器端使用的所有Deno模块。

服务器端渲染 (Server-side Rendering)

Now that we have imported all our modules in one central location, we can begin setting up our server. We will be utilizing Deno’s Oak middleware framework, and ReactDOMServer to render components to static markup.

现在,我们已将所有模块导入一个中央位置,我们可以开始设置服务器了。 我们将利用Deno的Oak中间件框架和ReactDOMServer将组件呈现为静态标记。

import { Application, Router, ReactDomServer } from './serverDeps.ts';
import { React } from './deps.ts';
import App from './client/app.tsx';
import { staticFileMiddleware } from './staticFileMiddleware.ts';


const PORT = 3000;


// Create a new server
const app = new Application();


// Router for base path
const router = new Router();


router.get('/', handlePage);


// Bundle the client-side code
const [_, clientJS] = await Deno.bundle('./client/client.tsx');


// Router for bundle
const serverrouter = new Router();
serverrouter.get('/static/client.js', (context) => {
  context.response.headers.set('Content-Type', 'text/html');
  context.response.body = clientJS;
});


// Implement the routes on the server
app.use(staticFileMiddleware);
app.use(router.routes());
app.use(serverrouter.routes());
app.use(router.allowedMethods());


app.addEventListener('listen', () => {
  console.log(`Listening at http://localhost:${PORT}`);
});
await app.listen({ port: PORT });


// Function to render entire application as a string
function handlePage(ctx: any) {
  try {
    const body = (ReactDomServer as any).renderToString(<App />);
    ctx.response.body = `<!DOCTYPE html>
  <html lang="en">
    <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/style.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">    
    <title>Rick and Morty</title>
    </head>
  <body >
    <div id="root">${body}</div>

    <script  src="/static/client.js" defer></script>
  </body>
  </html>`;
  } catch (error) {
    console.error(error);
  }
}

If you are familiar with Express.js and/or Koa.js the structure for creating routers and endpoints with the Oak framework above should be very familiar. If you skim through the code there are two main things that differ from what you may be used to: the Deno.bundle function on line 17 and the HTML file at the bottom of the code block.

如果您熟悉Express.js和/或Koa.js,那么使用上述Oak框架创建路由器和端点的结构应该非常熟悉。 如果您浏览了代码,则有两个主要的方面与您可能习惯的有所不同:第17行的Deno.bundle函数和代码块底部HTML文件。

The Deno.bundle function is one of the great features that Deno provides. Similar to how you would use a bundler like Webpack to transpile and compile your application in Node.js, Deno has that functionality out of the box. The Deno.bundle function takes an entry point of the client-side code as an argument and transpiles and bundles the client-side file structure into a single javascript file to be sent to the client.

Deno.bundle函数是Deno.bundle提供的重要功能之一。 与您使用像Webpack这样的打包器在Node.js中转译和编译应用程序的方式类似,Deno可以立即使用该功能。 Deno.bundle函数将客户端代码的入口点作为参数,并进行编译并将客户端文件结构捆绑到单个javascript文件中,以发送给客户端。

The second nuance above is the handlePage function, starting on line 38. When this function is invoked, it begins by utilizing the rendertoString function that is provided by the ReactDOMServer package. The React application is passed into this function and converts the entire application into an HTML string. So when a “GET” request for the root endpoint is received by the server, the entire React application is sent to the client as a string.

上面的第二个细微差别是handlePage函数,从第38行开始。调用此函数时,它首先利用ReactDOMServer包提供的rendertoString函数。 React应用程序传递到此函数中,并将整个应用程序转换为HTML字符串。 因此,当服务器收到对根端点的“ GET”请求时,整个React应用程序将作为字符串发送到客户端。

While the page does load faster, it is a marked down version of the page, meaning that it does not have any of the React functionality — this is why a request is made for the bundled javascript file on line 52. With server-side rendering, the React application never uses the render method and instead uses a hydrate method. Since the webpage is already rendered, the browser receives the bundled javascript file and parses through the rendered application, seamlessly reinjecting the React functionality into the application.

尽管该页面确实加载得更快,但这是该页面的标记版本,这意味着它不具有任何React功能-这就是为什么在第52行上请求捆绑的javascript文件的原因。服务器端渲染,React应用程序从不使用render方法,而是使用hydrate方法。 由于已经渲染了网页,因此浏览器会接收捆绑的javascript文件并通过渲染的应用程序进行解析,从而将React功能无缝地重新注入到应用程序中。

客户端代码和GraphQL (Client-side code and GraphQL)

Now that we have covered server-side rendering from the server-side, let's take a look at how we are able to achieve this functionality on the client-side.

现在我们已经从服务器端介绍了服务器端渲染,下面让我们看一下如何在客户端上实现此功能。

import { React, ReactDom } from '../deps.ts';
import App from './app.tsx';


// Hydrate the app and reconnect React functionality
(ReactDom as any).hydrate(<App />, document.getElementById('root'));

The code snippet above demonstrates the entry point into the client-side code. Notice how the hydrate method is used instead of render.

上面的代码段演示了客户端代码的入口点。 注意如何使用hydrate方法而不是render

Pretty simple, right? Well, let’s look into how we can incorporate GraphQL fetching and caching functionality into our application.

很简单,对吧? 好吧,让我们研究如何将GraphQL提取和缓存功能整合到我们的应用程序中。

import { React, ObsidianWrapper } from '../deps.ts';


import MainComponent from './DemoComponents/MainComponent.tsx';


declare global {
  namespace JSX {
    interface IntrinsicElements {
      div: any;
    }
  }
}


const App = () => {
  return (
    <ObsidianWrapper>
      <MainComponent />
    </ObsidianWrapper>
  );
};


export default App;

In order to cache our GraphQL requests, we will be using the ObsidianWrapper . Similar to how you would wrap your application in a provider when using a React state management library, utilizing this wrapper supplies caching capabilities to our GraphQL requests. This improves the performance of the app, providing consistent data throughout the application and reducing the load on the backend.

为了缓存GraphQL请求,我们将使用ObsidianWrapper 。 与使用React状态管理库时将应用程序包装在提供程序中的方式类似,利用此包装器可以为我们的GraphQL请求提供缓存功能。 这可以提高应用程序的性能,在整个应用程序中提供一致的数据,并减少后端的负载。

提取和缓存GraphQL请求 (Fetching and caching GraphQL requests)

Finally, we will be taking a look at how we will be fetching and caching our GraphQL requests in the following code block.

最后,我们将研究如何在以下代码块中获取和缓存GraphQL请求。

import { React, useObsidian } from '../../deps.ts';
import Sidebar from './Sidebar.tsx';
import Carousel from './Carousel.tsx';




declare global {
  namespace JSX {
    interface IntrinsicElements {
      h1: any;
      div: any;
    }
  }
}


const GET_CHARACTERS = `
  query{
    characters(page:1){
    results{
       id
       name
       image
      }
    }
  }
`;


const MainPage = () => {
  const [info, setInfo] = (React as any).useState({});
  const [characters, setCharacters] = (React as any).useState([]);


  const { gather } = useObsidian();


  (React as any).useEffect(() => {
    gather(GET_CHARACTERS, {
      endpoint: 'https://rickandmortyapi.com/graphql',
      destructure: false,
    }).then((resp: any) => setCharacters([...resp.data.characters.results]));
  }, []);


  return (
    <div id='main-container'>
      <h1>Rick and Morty Character Guide</h1>
      <div id='app-container'>
        <Sidebar info={info} />
        <Carousel characters={characters} setInfo={setInfo} />
      </div>
    </div>
  );
};


export default MainPage;

We will first begin by importing the useObsidian hook which allows us to access the functionality provided by the wrapper. On line 31 we invoke the hook which gives us access to a few different methods. Here we are using the gather method which gives us the ability to fetch and cache GraphQL requests. The first parameter of this method is the GraphQL query and the second is an “options” parameter. For the sake of simplicity, we are using an external API and specifying to not destructure the query and response since this requires us to provide the application with the GraphQL schema. If you are curious about Obsidian’s normalization and destructuring capabilities, check out the article below.

首先,我们将导入useObsidian挂钩,该挂钩允许我们访问包装器提供的功能。 在第31行,我们调用该钩子,该钩子使我们可以访问一些不同的方法。 这里我们使用的gather方法,它为我们提供了获取和缓存GraphQL请求的能力。 此方法的第一个参数是GraphQL查询,第二个参数是“选项”参数。 为简单起见,我们使用外部API并指定不破坏查询和响应,因为这要求我们为应用程序提供GraphQL模式。 如果您对黑曜石的标准化和解构功能感到好奇,请查看下面的文章。

结语 (Wrapping up)

Now that we have built our core structure, we can add some additional functionality to query for more specific query information about each individual character. Finally, we add some minor styling to wrap it all up!

现在我们已经建立了核心结构,我们可以添加一些附加功能来查询有关每个字符的更具体的查询信息。 最后,我们添加一些较小的样式以将其全部包装!

Image for post

If you would like to have a look at the source code you can find the repository at https://github.com/Alonsog66/GraphQL-Deno-Medium-Demo.

如果您想看一下源代码,可以在https://github.com/Alonsog66/GraphQL-Deno-Medium-Demo中找到存储库。

结论 (Conclusion)

And there you have it! As you can see there are some major changes when working with Deno as opposed to Node.js — we do not store external modules locally, TypeScript can be compiled out of the box, and we did not need to configure a webpack.config.js file to specify the compiling as Deno can natively perform all of the transpiling and bundling. If you have any questions about any of this material covered feel free to post a comment below or reach out via LinkedIn.

在那里,您拥有了! 如您所见,与Deno相比,与Node.js相比,使用Deno时有一些重大更改-我们不在本地存储外部模块,TypeScript可以直接编译,并且我们不需要配置webpack.config.js文件指定编译,因为Deno可以本地执行所有转码和捆绑。 如果您对本文涵盖的任何内容有任何疑问,请随时在下面发表评论或通过LinkedIn进行联系

Cheers!

干杯!

翻译自: https://medium.com/@alonsogarza6/building-an-ssr-react-application-with-graphql-and-deno-832c391bf8f2

deno使用rust

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值