golang react
by Chris Chuck
克里斯·查克(Chris Chuck)
With Go version 1.11, we now get an experimental version of WebAssembly. If you don’t know what WebAssembly is, don’t fret. In short, WebAssembly aims to bring high performance, assembly-like code into the browser. This allows developers to put more computationally intensive tasks into the browser, be it for a game or making some super cool animations.
使用Go版本1.11,我们现在可以获得WebAssembly的实验版本。 如果您不知道什么是WebAssembly,请不要担心。 简而言之,WebAssembly旨在将高性能的,类似于汇编的代码引入浏览器。 这使开发人员可以将更多计算密集型任务放到浏览器中,无论是用于游戏还是制作一些超酷的动画 。
So with that, I’m going to show you how to add Go-based WebAssembly to a React app! This guide assumes you have some familiarity with Webpack, Babel, and React. If you’re new to these technologies, I highly recommend you checkout this tutorial.
因此,我将向您展示如何将基于Go的WebAssembly添加到React应用程序! 本指南假定您对Webpack,Babel和React有所了解。 如果您不熟悉这些技术,强烈建议您阅读本教程 。
This tutorial will show you how to create a basic React app that utilizes WebAssembly for Go. In the near future, I’ll show you how to build a tic-tac-toe game in which the computer is 100% unbeatable and we’ll use WebAssembly to power the minimax algorithm (don’t worry, it sounds harder than it is!) ?
本教程将向您展示如何创建一个利用WebAssembly for Go的基本React应用。 在不久的将来,我将向您展示如何构建井字游戏,在该游戏中计算机100%无与伦比,并且我们将使用WebAssembly来支持minimax算法(别担心,这听起来比它更难是!)
The code for this part (and future parts) will be on Github here.
对于这部分(以及将来的部件)的代码将在Github 这里 。
Make sure you have Go 1.11 (minimum) and Node.js installed.
确保已安装Go 1.11(最低版本)和Node.js。
I am using Chrome version 69 and all current versions of Edge, Firefox, and Safari have WebAssembly support. However, results from this tutorial may vary based on version/browser.
我正在使用Chrome版本69,并且Edge,Firefox和Safari的所有当前版本都具有WebAssembly 支持 。 但是,本教程的结果可能会因版本/浏览器而异。
Jumping right into it, create a folder and cd
into it.
跳到该文件夹中,创建一个文件夹并cd
进入该文件夹。
Inside that folder create a client
and a server
folder.
在该文件夹内创建一个client
和一个server
文件夹。
Let’s start with building the React App. It’s nothing more than a regular client side rendered app with a few extra bits added in!
让我们从构建React App开始。 它不过是一个普通的客户端渲染应用程序,其中添加了一些额外的功能!
First cd
into the client
folder and run npm init -y
to initialize your package.json
.
首先cd
进入client
文件夹,然后运行npm init -y
初始化package.json
。
After that, run the following:
之后,运行以下命令:
npm install --save react react-dom && npm install --save-dev @babel/core @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-syntax-dynamic-import @babel/polyfill @babel/preset-env @babel/preset-react add-asset-html-webpack-plugin babel-loader html-webpack-plugin webpack webpack-cli webpack-dev-server
Once you do that, change the scripts
portion of your package.json
to the following:
完成后,将package.json
的scripts
部分更改为以下内容:
"scripts": { "dev": "webpack-dev-server --mode development", "build": "webpack --mode production"},
Next, in the client folder, create two files, a .babelrc
and a webpack.config.js
.
接下来,在客户端文件夹中,创建两个文件, .babelrc
和webpack.config.js
。
In the .babelrc
paste the following:
在.babelrc
粘贴以下内容:
{ "presets": [ ["@babel/preset-env", { "modules": false } ], "@babel/preset-react"], "plugins": [ "@babel/plugin-proposal-class-properties", ["@babel/plugin-proposal-decorators", { "legacy": true }], "@babel/plugin-syntax-dynamic-import" ]}
And in the webpack.config.js
paste the following:
然后在webpack.config.js
粘贴以下内容:
Note the AddAssetHtmlPlugin
which we are using to inject the wasm_exec.js
file and init_go.js
file into our app via a script tag. These must be in the order they are shown so that the wasm_exec.js
file runs before init_go.js
file. The wasm_exec.js
simply sets up Go’s runtime on the browser and the init_go.js
file gives us a global, workable Go object instance. But more on these files later.
请注意AddAssetHtmlPlugin
,我们将其wasm_exec.js
通过脚本标签将wasm_exec.js
文件和init_go.js
文件注入到我们的应用程序中。 它们必须按照显示顺序排列,以便wasm_exec.js
文件在init_go.js
文件之前运行。 wasm_exec.js
只是在浏览器上设置Go的运行时,而init_go.js
文件为我们提供了一个全局的,可行的Go对象实例。 但是稍后会详细介绍这些文件。
Now create a src
folder and add an index.js
file, index.html
file, init_go.js
file, wasm_exec.js
file, and a components
folder with an app.js
file in it. Your directory should look like so:
现在创建一个src
文件夹,并添加一个index.js
文件, index.html
文件, init_go.js
文件, wasm_exec.js
文件以及其中包含app.js
文件的components
文件夹。 您的目录应如下所示:
From here, add this to your index.html
:
在这里,将其添加到您的index.html
:
In the index.js
add this:
在index.js
添加以下内容:
And in your components/app.js
file add the following:
并在components/app.js
文件中添加以下内容:
Now we have an extremely basic React app!
现在我们有了一个非常基础的React应用程序!
In the wasm_exec.js
file, paste the code from here (omitted for brevity).
在wasm_exec.js
文件中,从此处粘贴代码(为简洁起见, 此处省略)。
Like we said before, this just instantiates the basic runtime for Go in the client. It provides a global Go
constructor that we’ll be using later.
就像我们之前说的,这只是实例化了客户端中Go的基本运行时。 它提供了一个全局的Go
构造函数,稍后我们将使用它。
Next we need to actually do something with that Go
object. So in your init_go.js
file, add the following:
接下来,我们需要对该Go
对象进行实际操作。 因此,在您的init_go.js
文件中,添加以下内容:
All this does is create a new go
object from the Go
constructor we made earlier and bind it to global state.
这一切都是从我们之前创建的Go
构造函数创建一个新的go
对象,并将其绑定到全局状态。
Go ahead and run npm run dev
and the navigate to localhost:8080
in the browser and you should see “Hello!” on your webpage. Not very interesting right? But what you don’t see is that we’ve injected our global go
object!
继续运行npm run dev
并在浏览器中导航到localhost:8080
,您应该看到“ Hello!”。 在您的网页上。 不是很有趣吧? 但是您看不到的是我们已经注入了全局go
对象!
Now change your components/app.js
file to the following:
现在,将您的components/app.js
文件更改为以下内容:
What did we change? Let’s start with the simple stuff. First we added an isLoading
attribute to state. This is so we know that WebAssembly is still loading. In the render
function, we use the isLoading
attribute from state to conditionally render a div
that says “Loading” or a button
.
我们改变了什么? 让我们从简单的东西开始。 首先,我们向状态添加了isLoading
属性。 因此,我们知道WebAssembly仍在加载。 在render
函数中,我们使用isLoading
属性有条件地渲染一个表示“ Loading”或button
的div
。
You may be asking yourself, “That button has an onClick
with a function sayHi
, but I don’t see a sayHi
function anywhere.” This is where WebAssembly comes in. When we write our Go code, we’ll be defining that function and binding it to global state there. This is why we must wait for WebAssembly to load before we can render our button. But we’ll fill in these blanks later.
您可能会问自己:“该按钮具有一个带有sayHi
函数的onClick
,但在任何地方都看不到sayHi
函数。” 这就是WebAssembly出现的地方。当我们编写Go代码时,我们将定义该函数并将其绑定到那里的全局状态。 这就是为什么我们必须等待WebAssembly加载后才能呈现按钮。 但是我们稍后将填写这些空白。
Looking at the componentDidMount
function, you can see we’re calling WebAssembly.instantiateStreaming
which is the optimal way of loading WebAssembly code. It takes a promise that returns a wasm
file and an importObject
as its parameters. It returns a compiled WebAssembly module. That promise is a fetch request to our API (we’ll build it next!) and that endpoint just returns a wasm
file. After we get the module, we use go
to run it and then we set isLoading
to false
.
查看componentDidMount
函数,您可以看到我们正在调用WebAssembly.instantiateStreaming
,这是加载WebAssembly代码的最佳方法 。 它承诺返回一个wasm
文件和一个importObject
作为其参数。 它返回一个已编译的WebAssembly模块。 这个承诺是对我们的API的提取请求(我们将在下一个构建它!),该端点仅返回wasm
文件。 获取模块后,使用go
运行它,然后将isLoading
设置为false
。
But of course, since we have nothing on localhost:3000
this will break.
但是,当然,因为我们在localhost:3000
上什么都没有,所以这会中断。
Now we need to setup the server to serve our wasm
file. First, open up a new terminal and cd
into the server
folder you made earlier and run npm init -y
to initialize your package.json
.
现在我们需要设置服务器来提供wasm
文件。 首先,打开一个新终端,并cd
到您之前创建的server
文件夹中,然后运行npm init -y
初始化package.json
。
Next, let’s install some packages. Run the following:
接下来,让我们安装一些软件包。 运行以下命令:
npm install --save compression cors express && npm install --save-dev nodemon
Change the scripts
portion of your package.json
to this:
将package.json
的scripts
部分更改为此:
"scripts": { "dev": "nodemon index.js"},
Now in the server
directory, create an index.js
file and a go
folder. In that go
folder, create a main.go
file.
现在在server
目录中,创建一个index.js
文件和一个go
文件夹。 在该go
文件夹中,创建一个main.go
文件。
Your folder should look like this:
您的文件夹应如下所示:
In the index.js
paste the following:
在index.js
粘贴以下内容:
This is just a simple express server which serves up a wasm
file from the go
folder. Let’s make that now!
这只是一个简单的快递服务器,它从go
文件夹提供wasm
文件。 现在就开始做吧!
In your main.go
file add this (big thanks to TutoiralEdge for his tutorial):
在您的main.go
文件中添加以下内容(非常感谢TutoiralEdge的教程 ):
Let’s break this down. First we need to import fmt
for basic printing and syscall/js
so we can use all of Go’s new JavaScript goodies. Next we’ll create our sayHi
function with parameters args []js.Value
even though we’re not going to pass in any arguments. All this function does is print “Hi!”
让我们分解一下。 首先,我们需要导入fmt
进行基本的打印和syscall/js
以便可以使用Go的所有新JavaScript好东西 。 接下来,即使我们不传递任何参数,也将使用参数args []js.Value
创建我们的sayHi
函数。 该功能仅打印“ Hi!”
In the registerCallbacks
function, we bind our function to global state in our browser. Now when we call js.Global().Set
function we’re going to first name our global variable “sayHi” and then pair it with our sayHi
function from above by wrapping it in the js.NewCallback
function.
在registerCallbacks
函数中,我们将函数绑定到浏览器中的全局状态。 现在,当我们调用js.Global().Set
函数时,我们将首先命名全局变量“ sayHi”,然后通过将其包装在js.NewCallback
函数中,将其与我们的sayHi
函数js.NewCallback
。
Lastly, in our main
function, we’re opening up a channel and running registerCallbacks
. The channel simply stalls our Go code so it doesn’t finish executing.
最后,在我们的main
功能中,我们打开一个通道并运行registerCallbacks
。 该通道只是停顿了我们的Go代码,因此无法完成执行。
Now all that’s left is compiling this Go code into WebAssembly.
现在剩下的就是将Go代码编译为WebAssembly。
cd
into the go
folder and run the following:
cd
进入go
文件夹并运行以下命令:
GOOS=js GOARCH=wasm go build -o main.wasm
Notice that our GOOS
is set to js
and our GOARCH
is set to wasm
. This means that our target operating system is js
and the compilation architecture is wasm
.
注意,我们的GOOS
设置为js
,我们的GOARCH
设置为wasm
。 这意味着我们的目标操作系统是js
,编译架构是wasm
。
Your folder structure should be this now:
您的文件夹结构应该是这样的:
As you can see, now we have a main.wasm
file we can serve.
如您所见,现在我们可以提供一个main.wasm
文件。
cd
back into the server
folder and run npm run dev
.
cd
返回server
文件夹并运行npm run dev
。
Your server should now be running on localhost:3000
. Go back to localhost:8080
(assuming you still have the client running) in your browser and refresh it. After it loads, open up the console and click the button. It should print “Hi!” in the console.
您的服务器现在应该在localhost:3000
上运行。 返回到浏览器中的localhost:8080
(假设您仍在运行客户端)并刷新它。 加载后,打开控制台并单击按钮。 它应该打印“嗨!” 在控制台中。
As you probably saw, it’ll say “Loading” for quite some time before our button appears. This is the overhead we incur from using WebAssembly. However, after this initial load, we can bask in low level, high performance glory.
您可能已经看到,在我们的按钮出现之前,它会说“正在加载”一段时间。 这是我们使用WebAssembly产生的开销 。 但是,在此初始负载之后,我们可以享受低水平,高性能的荣耀。
To kill the client and server, just press ctrl + c
in your terminals.
要终止客户端和服务器,只需在终端中按ctrl + c
。
Thank you for reading and I hope you enjoyed learning about WebAssembly with me. While this is an extremely basic implementation of WebAssembly in React, in the next part of this series, we’ll be making an AI agent that’s unbeatable at tic-tac-toe. So stay tuned if you’re interested in that!
感谢您的阅读,希望您喜欢和我一起学习WebAssembly。 尽管这是React中WebAssembly的一个极其基本的实现,但是在本系列的下一部分中,我们将制作一个在井字游戏中无与伦比的AI代理。 因此,如果您对此感兴趣,请继续关注!
If you have any comments or questions feel free to leave them below.
如果您有任何意见或疑问,请随时将其留在下面。
Thanks again for reading! Please share, drop a ? (or two), and happy coding.
再次感谢您的阅读! 请分享,删除一个 ? ( 或两个),并且编码愉快。
Add me on LinkedIn!
在LinkedIn上加我!
翻译自: https://www.freecodecamp.org/news/taking-off-with-webassembly-for-go-in-react-7c099bd907fa/
golang react