步骤:

创建一个新项目

新建项目并将命令终端当前目录移至项目根目录;

为项目安装 React 框架

  • 通过运行以下命令安装 React 模块:
npm install --save react react-dom
  • 通过运行以下命令安装所需的TypeScript语言编译器加载程序:
npm install --save-dev typescript ts-loader
  • 通过运行以下命令安装所需的CSS加载器:
npm install --save-dev style-loader css-loader

如果npm install 命令报告了一个漏洞,您可能还需要运行npm audit fix命令,以便在继续之前尝试修复报告的漏洞。

NOTE
作为安装这些模块的替代方案,您可以编辑默认的
package.json文件添加项目的依赖项
{
  "name": "contacts_assets",
  "version": "0.1.0",
  "description": "",
  "keywords": [],
  "scripts": {
    "build": "webpack"
  },
  "devDependencies": {
    "assert": "2.0.0",
    "buffer": "6.0.3",
    "css-loader": "^5.2.1",
    "events": "3.3.0",
    "html-webpack-plugin": "5.3.1",
    "process": "0.11.10",
    "stream-browserify": "3.0.0",
    "style-loader": "^2.0.0",
    "terser-webpack-plugin": "5.1.1",
    "ts-loader": "^8.1.0",
    "typescript": "^4.2.4",
    "util": "0.12.3",
    "webpack-cli": "4.5.0",
    "webpack": "5.24.4"
  },
  "dependencies": {
    "@dfinity/agent": "0.10.0",
    "@dfinity/candid": "0.10.0",
    "@dfinity/principal": "0.10.0",
    "react-dom": "^17.0.2",
    "react": "^17.0.2"
  }
}

这个示例 package.json 文件中的 JavaScript 代理的版本是0.10.0。但是,在大多数情况下,您希望使用可用的agent的最新版本。当您创建一个新项目时,dfx new 命令会自动为您检索 JavaScript 代理的最新版本。您还可以在创建项目之后通过运行 npm install --save @dfinity/agent 命令手动检索最新版本。

修改默认程序

1、在文本编辑器中打开 src/contacts/main.mo 文件并删除现有内容。

2、将下面的示例代码复制并粘贴到文件中:

import List "mo:base/List";
import AssocList "mo:base/AssocList";

actor Contact {

  var contacts : ContactsMap = List.nil();

  type Name = Text;
  type Phone = Nat;

  type Entry = {
    name : Name;
    address1 : Text;
    address2 : Text;
    email : Text;
    phone : Phone;
  };

  type ContactsMap = AssocList.AssocList<Name, Entry>;

  func nameEq(lhs : Name, rhs : Name) : Bool {
    return lhs == rhs;
  };

  public func insert(name : Name, address1 : Text, address2 : Text, email : Text, phone : Phone) : async () {
     let newEntry : Entry = {
       name;
       address1;
       address2;
       email;
       phone;
     };

     let (newContacts, _) = AssocList.replace(
       contacts,
       name,
       func(n: Name, m: Name) : Bool { n == m },
       ?newEntry
     );
     contacts := newContacts;
  };

  public query func lookup(name : Name) : async ?Entry {
    return AssocList.find(contacts, name, nameEq);
  };
};

3、保存您的更改并关闭 main.mo 文件以继续。

修改前端文件

现在可以为程序创建一个新的前端了。

1、在文本编辑器中打开 webpack 配置文件(webpack.config.js)。

2、修改前端条目,用 index.jsx 替换默认索引.html。

entry: {
  // The frontend.entrypoint points to the HTML file for this build, so we need
  // to replace the extension to `.js`.
  index: path.join(__dirname, asset_entry).replace(/\.html$/, ".jsx"),
},

3、找到plug部分上面的modulekey的注释示例,然后取消注释以下行:

module: {
  rules: [
    { test: /\.(js|ts)x?$/, loader: "ts-loader" },
    { test: /\.css$/, use: ['style-loader','css-loader'] }
  ]
},

4、这些设置使您的程序能够使用 ts-loader 编译器并导入 CSS 文件。

注意: 如果你想添加对. scss 或. sass 文件的支持,你应该安装 sass-loader:

npm install --save react react-dom

然后在 webpack.config.js 中的 css-loader 规则之下添加这个附加规则:

module: {
  rules: [
    // ...
    {
      test: /\.s[ac]ss$/i,
      use: [
        // Creates `style` nodes from JS strings
        "style-loader",
        // Translates CSS into CommonJS
        "css-loader",
        // Compiles Sass to CSS
        "sass-loader",
      ],
    },
  ]
},

5、保存更改并关闭 webpack.config.js 文件继续。

6、在项目的根目录中创建一个名为 tsconfig.json 的新文件。

7、在文本编辑器中打开 tsconfig.json 文件,然后将以下内容复制粘贴到文件中:

{
    "compilerOptions": {
      "target": "es2018",        /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
      "lib": ["ES2018", "DOM"],  /* Specify library files to be included in the compilation. */
      "allowJs": true,           /* Allow javascript files to be compiled. */
      "jsx": "react",            /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    },
    "include": ["src/**/*"],
}

8、保存更改并关闭 tsconfig.json 文件以继续。

向项目中添加样式表

现在可以创建新的级联样式表并将其添加到项目中。

1、更改到 src/contacts _ assets/assets 目录。

2、在文本编辑器中打开 main.css 文件并删除现有内容。

3、为前端定义一些样式属性。例如,复制并粘贴以下样式到文件中:

html {
    background-color: bisque;
}

body {
    font-family: Arial, Helvetica, sans-serif;
    display: block;
    margin: 10px;
}

h1 {
    color: darkblue;
    font-size: 32px;
}

div.new-entry {
    margin: 30px 20px 30px 20px;
}

.new-entry > div {
    margin-bottom: 15px;
}

table {
    margin-top: 12px;
    border-top: 1px solid darkblue;
    border-bottom: 1px solid darkblue;
}

#form {
    margin: 30px 0 30px 20px;
}

button {
    line-height: 20px;
}

#lookupName {
    margin-right: 12px;
}

4、保存更改并关闭 main.css 文件,重命名为mycontacts.css以继续。

5、更改为 src/contacts _ assets/src 目录。

cd ../src

6、在文本编辑器中打开默认 index.js 文件并删除现有内容。

7、复制并粘贴以下示例代码到 index.js 文件中:

import * as React from "react";
import { render } from "react-dom";
import { contacts } from "../../declarations/contacts";
import "../assets/mycontacts.css";

const Contact = () => {
  async function doInsert() {
    let name = document.getElementById("newEntryName").value;
    let add1 = document.getElementById("newEntryAddress1").value;
    let add2 = document.getElementById("newEntryAddress2").value;
    let email = document.getElementById("newEntryEmail").value;
    let phone = document.getElementById("newEntryPhone").value;
    contacts.insert(name, add1, add2, email, parseInt(phone, 10));
  }

  async function lookup() {
    let name = document.getElementById("lookupName").value;
    contacts.lookup(name).then((opt_entry) => {
      let entry;

      if (opt_entry.length == 0) {
        entry = { name: "", description: "", phone: "" };
      } else {
        entry = opt_entry[0];
      }

      document.getElementById("newEntryName").value = entry.name;
      document.getElementById("newEntryAddress1").value = entry.address1;
      document.getElementById("newEntryAddress2").value = entry.address2;
      document.getElementById("newEntryEmail").value = entry.email;
      document.getElementById("newEntryPhone").value = entry.phone.toString();
    });
  }

  return (
    <div className="new-entry">
      <h1>My Contacts</h1>
      <div>
        Add or update contact information:
        <form id="contact">
          <table>
            <tbody>
              <tr>
                <td>Name:</td>
                <td>
                  <input id="newEntryName"></input>
                </td>
              </tr>
              <tr>
                <td>Address 1 (street):</td>
                <td>
                  <input id="newEntryAddress1"></input>
                </td>
              </tr>
              <tr>
                <td>Address 2 (city and state):</td>
                <td>
                  <input id="newEntryAddress2"></input>
                </td>
              </tr>
              <tr>
                <td>Email:</td>
                <td>
                  <input id="newEntryEmail"></input>
                </td>
              </tr>
              <tr>
                <td>Phone:</td>
                <td>
                  <input id="newEntryPhone" type="number"></input>
                </td>
              </tr>
            </tbody>
          </table>
        </form>
      </div>
      <div>
        <button onClick={() => doInsert()}>Add Contact</button>
      </div>
      <div>
        Lookup name:{" "}
        <input id="lookupName" style={{ lineHeight: "20px" }}></input>
        <button onClick={() => lookup()}>Lookup</button>
      </div>
    </div>
  );
};

document.title = "DFINITY CONTACT EXAMPLE";

render(<Contact />, document.getElementById("contacts"));

8、通过运行以下命令,将修改后的 index.js 文件重命名为 index.jsx:

mv index.js index.jsx

9、在文本编辑器中打开默认的 src/contacts_assets/src/index.html 文件,然后删除 main.css 链接,并用 <div id = "contacts" > </div> 更新 body 内容。

例如:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>contacts</title>
    <base href="/" />
  </head>
  <body>
    <main>
      <div id="contacts"></div>
    </main>
  </body>
</html>

10、返回到项目目录的根目录。

启动本地网络

在本地启动环境:

dfx start --background

注册、构建和部署 dapp

部署 dapp:

1、如果需要,检查您是否仍然在项目的根目录中。

2、通过运行以下命令注册、构建和部署 dapp:

dfx deploy

若要在 Internet 计算机区块链上部署罐,您必须指定您正在部署到 Internet 计算机而不是您的本地环境,使用 -- network 命令行选项:

dfx deploy --network=ic

PS: 部署完可以直接通过asset canister的principal对前端进行访问,例如:https://6neag-ryaaa-aaaai-qfikq-cai.raw.ic0.app

3、启动 Webpack 开发服务器:

npm start

查看前端

1、打开浏览器,导航到 http://localhost:8080。(或http://localhost:8000/?canisterId=${asset canister ID}或http://localhost:8080/?canisterId=${asset canister ID})

NOTE
需要注意的是,dfx deploy后监听的端口是8000,npm start后监听的端口是8080。我们可以用localhost:8080直接访问到项目前端,而不能用localhost:8000直接访问,需要在后面加canisterId这个参数(由此可以看出dfx start和npm start开启的两个服务的关系)

2、验证内容是否正确,例如:

mycontacts-form.png

3、通过在 Name、 Address 和 Email 输入字段中输入文本以及在 Phone 输入字段中输入编号,然后单击 Add Contact,创建一个或多个测试记录。

4、清除表单字段并在 Lookup name 字段中键入联系人名称,然后单击 Lookup 查看存储的联系人信息。

请记住,您键入的 Lookup 名称必须与添加的联系人的名称完全匹配。

修改样式表并测试更改

查看完 Contacts dapp 后,您可能需要做一些更改。要更改样式表属性:

在文本编辑器中打开 src/contacts_assets/assets/mycontacts.css文件,并修改其样式设置。

例如,您可能希望更改输入表单的背景颜色或样式。

您应该在打开的浏览器窗口中立即看到更新。

修改前端或后端代码

如果您希望进一步了解,您可能希望尝试修改本教程的前端或后端代码。例如,你可以尝试修改教程来做以下事情:

在添加新联系人(例如,作为 onClick 事件的一部分)之后,更改前端代码以清除输入字段。

将 Motoko 程序函数更改为执行部分匹配,而不是在 Name 字段上执行精确的字符串匹配。(您需要运行 dfx 部署,以在本地环境上测试您的更改)

更改 Motoko 程序以允许基于不同字段的查找。

停止本地canister执行环境

在完成对程序的试验之后,可以停止本地环境,这样它就不会在后台继续运行。

停止本地的发展环境:

1、在显示 webpack dev 服务器的终端中,按 Control-C 中断开发服务器。

2、运行以下命令停止互联网电脑网络:

dfx stop
logo-1024x751.png

A Student on the way to full stack of Web3.