前端概述
Internet Computer platform 允许您使用我们的 JavaScript 代理 为您的 dapp 托管 Web 3.0 前端。 通过使用 dfx
提供的 asset canister 将静态文件上传到 Internet Computer,您将能够在去中心化技术上运行您的整个应用程序。 本节详细介绍了由 dfx new
提供的默认前端模板、前端配置选项以及使用其他框架为您的项目构建用户界面。
以下是一些教程的快速链接,其中包含开发前端 dapp 各个阶段的示例代码:
-
构建 React dapp 的教程自定义前端
-
使用 Candid 作为基本接口来公开和测试容器中的功能。
-
使用 raw HTML and JavaScript 来显示一个简单的 HTML 入口页面。
-
使用 React and compiled JavaScript 将 HTML 属性和元素直接嵌入到页面中。
-
使用 React 和 TypeScript 从外部文件导入 CSS 属性。
如何使用默认模板
您可能已经在教程中注意到,项目包括模板 index.js
和 webpack.config.js
文件。
默认情况下,index.js
文件会导入位于 src/declarations
文件夹中的代理。当您在本地或部署到 IC 时运行 dfx deploy
时,dfx
将生成该目录。
生成的代码将如下所示:
import { Actor, HttpAgent } from "@dfinity/agent";
// Imports candid interface
import { idlFactory } from './hello.did.js';
// CANISTER_ID is replaced by webpack based on node enviroment
export const canisterId = process.env.HELLO_CANISTER_ID;
/**
*
* @param {string | Principal} canisterId Canister ID of Agent
* @param {{agentOptions?: import("@dfinity/agent").HttpAgentOptions; actorOptions?: import("@dfinity/agent").ActorConfig}} [options]
* @return {import("@dfinity/agent").ActorSubclass<import("./hello.did.js")._SERVICE>}
*/
export const createActor = (canisterId, options) => {
const agent = new HttpAgent({ ...options?.agentOptions });
// Fetch root key for certificate validation during development
if(process.env.NODE_ENV !== "production") agent.fetchRootKey();
// Creates an actor with using the candid interface and the HttpAgent
return Actor.createActor(idlFactory, {
agent,
canisterId,
...options?.actorOptions,
});
};
/**
* A ready-to-use agent for the hello canister
* @type {import("@dfinity/agent").ActorSubclass<import("./hello.did.js")._SERVICE>}
*/
export const hello = createActor(canisterId);
然后,如果你返回到`index.js,你可以看到它获取了生成的actor,并使用它来调用
hello`容器的`greet`方法:
import { hello } from "../../declarations/hello";
document.getElementById("clickMeBtn").addEventListener("click", async () => {
const name = document.getElementById("name").value.toString();
// Interact with hello actor, calling the greet method
const greeting = await hello.greet(name);
document.getElementById("greeting").innerText = greeting;
});
在许多项目中,您将能够使用 declarations
下的代码而无需任何更改,并在 hello_assets/src
中进行更改。 但是,如果您的项目有其他要求,请继续阅读下文。
修改 webpack 配置
由于 webpack 是基于 JavaScript 的应用程序的流行且高度可配置的模块捆绑器,因此新项目会创建一个默认的 webpack.config.js
文件,以便轻松添加特定模块,例如 react
和 markdown
——你想用的。
如果您查看模板 webpack.config.js
文件中的代码,您会发现它从 .dfx/local/canister_ids.json
和 './canister_ids.json 推断出容器 ID '
用于您配置的任何其他环境。 它根据“DFX_NETWORK”过程变量或“NODE_ENV”是否设置为“生产”来决定使用哪个网络。
您可以在以下代码块中看到这些步骤:
let localCanisters, prodCanisters, canisters;
try {
localCanisters = require(path.resolve(".dfx", "local", "canister_ids.json"));
} catch (error) {
console.log("No local canister_ids.json found. Continuing production");
}
function initCanisterIds() {
try {
prodCanisters = require(path.resolve("canister_ids.json"));
} catch (error) {
console.log("No production canister_ids.json found. Continuing with local");
}
const network =
process.env.DFX_NETWORK ||
(process.env.NODE_ENV === "production" ? "ic" : "local");
canisters = network === "local" ? localCanisters : prodCanisters;
for (const canister in canisters) {
process.env[canister.toUpperCase() + "_CANISTER_ID"] =
canisters[canister][network];
}
}
initCanisterIds();
输入输出配置
在很多情况下,您可以直接使用默认的 webpack.config.js
文件,无需任何修改,也可以添加插件、模块和其他自定义配置以满足您的需求。
您对 webpack.config.js
配置所做的具体更改很大程度上取决于您要使用的其他工具和框架。
例如,如果您尝试过 自定义前端 或 Add a stylesheet 前端教程,您可能有 修改了以下部分以使用 React JavaScript:
module: {
rules: [
{ test: /\.(ts|tsx|jsx)$/, loader: "ts-loader" },
{ test: /\.css$/, use: ['style-loader','css-loader'] }
]
}
};
}
如果您的应用程序不使用 dfx
来运行构建脚本,您可以自己提供变量。 例如:
DFX_NETWORK=staging NODE_ENV=production HELLO_CANISTER_ID=rrkah... npm run build
确保节点在项目中可用
因为项目依赖 webpack 为默认前端提供框架,所以您必须在开发环境中安装 node.js
并且可以在项目目录中访问。
-
如果您想在不使用默认 webpack 配置和容器别名的情况下开发项目,您可以从
dfx.json
文件中删除assets
容器或使用特定容器名称构建项目。 例如,您可以通过运行以下命令选择仅构建没有前端资产的 hello 程序:dfx build hello
-
如果你使用默认的 webpack 配置并且运行
dfx build
失败,你应该尝试在项目目录中运行npm install
然后重新运行dfx build
。 -
如果在项目目录中运行
npm install
不能解决问题,您应该检查webpack.config.js
文件的配置是否有语法错误。
在 React 框架中使用其他模块
几个教程和示例项目examples 存储库说明了如何使用 npm install
命令添加 React 模块。
您可以使用这些模块来构建您想要在项目中使用的用户界面组件。
例如,您可以运行以下命令来安装 react-router
模块:
npm install --save react react-router-dom
然后,您可以使用该模块构建类似于以下内容的导航组件:
import React from 'react';
import { NavLink } from 'react-router-dom';
const Navigation = () => {
return (
<nav className="main-nav">
<ul>
<li><NavLink to="/myphotos">Remember</NavLink></li>
<li><NavLink to="/myvids">Watch</NavLink></li>
<li><NavLink to="/audio">Listen</NavLink></li>
<li><NavLink to="/articles">Read</NavLink></li>
<li><NavLink to="/contribute">Write</NavLink></li>
</ul>
</nav>
);
}
export default Navigation;
使用 webpack-dev-server 更快地迭代
从 dfx 0.7.7 开始,我们现在在 dfx new
启动器中为您提供 webpack dev-server。
webpack 开发服务器——webpack-dev-server
——提供对 webpack 资产的内存访问,使您能够使用实时重新加载进行更改并立即在浏览器中看到它们的反映。
要利用 webpack-dev-server
:
-
创建一个新项目并切换到您的项目目录。
-
如有必要,在本地启动 Internet Computer,然后像往常一样进行部署,例如,通过运行
dfx deploy
命令。 -
通过运行以下命令启动 webpack 开发服务器:
npm start
-
打开 Web 浏览器并使用端口 8080 导航到应用程序的资产容器。
例如:
http://localhost:8080
-
打开一个新的终端窗口或选项卡并导航到您的项目目录。
-
在文本编辑器中打开项目的
index.js
文件并更改内容。例如,您可以使用 JavaScript 向页面添加一个元素:
document.body.onload = addElement;
document.body.onload = addElement; function addElement () { // create a new div element const newDiv = document.createElement("div"); // and give it some content const newContent = document.createTextNode("Test live page reloading!"); // add the text node to the newly created div newDiv.appendChild(newContent); // add the newly created element and its content into the DOM const currentDiv = document.getElementById("div1"); document.body.insertBefore(newDiv, currentDiv); }
-
将您的更改保存到
index.js
文件,但让编辑器保持打开状态以继续进行更改。 -
刷新浏览器或等待它自行刷新以查看您的更改。
完成项目的前端工作后,可以按 Control-C 停止 webpack 开发服务器。
使用其他框架
您可能想要使用 webpack 以外的捆绑器。 每个捆绑器的说明尚未准备好,但如果您熟悉您的捆绑器,以下步骤应该可以帮助您:
-
从
package.json
中删除copy:types
、prestart
和prebuild
脚本 -
运行
dfx deploy
为您的容器生成本地绑定 -
将生成的绑定复制到您要保留它们的目录
-
修改
declarations/<canister_name>/index.js
并将process.env.<CANISTER_NAME>_CANISTER_ID
替换为打包程序的环境变量的等效模式-
如果这是您首选的工作流程,则可以对容器 ID 进行硬编码
-
-
提交声明并将它们导入您的代码库