Deno
Environment developmentOak-orm-mysql-reactjs
The whole stack application
Deno
Environment developmentOak-orm-mysql-reactjs
The whole stack application- What is Deno?
- (I) Modern features based on JavaScript language
- (2) Install Deno
- Command line
- Command line options
- (5) Deno code examples
- (6) Standard library
- A simple example of full stack application
- (I) The basic contents of the project are as follows
- (2) Establish project folders
- (3) Centralized management dependency
- Create env.ts
- Create server.ts file
- (6) Start the application program
- (7) Create a router
- (8) Add controller, API call function:
- (9) Implement the method of adding, deleting, modifying and checking
- 1. Query data method:
- 2. New data method:
- 3. Update and delete methods:
- Mysql and ORM support
- 1. The Model is a Model
- 2. Connect to the database
- 3. Configure the database connection
- (11) Introduction of password authentication
- Third, client trial
- Reactjs support
- (2) Set App components
- (3) Route setting
- Use the helper for the actual rendering
- (4) Pages and components
- 1. The App components
- 2. LoginComponent components
- 4. Debug Deno
- Chrome Devtools
- (2) VSCode
- The source address
- More Resources
- What is Deno?
What is Deno?
Deno is a JavaScript and TypeScript runtime based on the V8 JavaScript engine and the Rust programming language that uses a secure environment to execute code by default.
It was created by Ryan Dahl, the original creator of Node.js, with a focus on security and productivity.
Deno is built on V8, Rust, and Tokio.
Two pronunciations, “Deno” and “Tino,” which would be more appropriate because the Deno logo is a dinosaur. Dinosaur stands for dino.
Deno is like Node, but has been greatly improved in many ways.
At the time of this writing, deno has just released its favorite version of 1.1.0, with numerous bug fixes and improved performance.
Start with the Deno feature list:
(I) Modern features based on JavaScript language
- A comprehensive standard library
- TypeScript support is included
- Includes ES module
- There is no package manager
- Have first-class await
- Built-in testing
- Remain browser compatible, with fetch and global Window objects built in
(2) Install Deno
I’m using Windows 10 on the WSL Debian Buster system. You can install it like this
Open the CMD command line and type WSL or bash
Then type:
curl -fsSL https://deno.land/x/install/install.sh | sh
Copy the code
Tips:
PowerShell (Windows):
iwr https://deno.land/x/install/install.ps1 -useb | iex
Copy the code
Homebrew (Mac):
brew install deno
Copy the code
Chocolatey (Windows):
choco install deno
Copy the code
Command line
Set the environment variables in ~/.bashrc
export DENO_INSTALL="$HOME/.deno"
export PATH="$DENO_INSTALL/bin:$PATH"
Copy the code
Once that’s done, you’ll have access to the deno command. Use deno –help to get help:
Deno -- help deno 1.1.0 A secure JavaScript and TypeScript runtime Docs: https://deno.land/std/manual.md Modules: https://deno.land/std/ https://deno.land/x/ Bugs: https://github.com/denoland/deno/issues To start the REPL, supply no arguments: deno To execute a script: deno run https://deno.land/std/examples/welcome.ts deno https://deno.land/std/examples/welcome.ts To evaluate codein the shell:
deno eval "console.log(30933 + 404)"
Run 'deno help run' for 'run'-specific flags.
USAGE:
deno [OPTIONS] [SUBCOMMAND]
OPTIONS:
-h, --help
Prints help information
-L, --log-level <log-level>
Set log level [possible values: debug, info]
-q, --quiet
Suppress diagnostic output
By default, subcommands print human-readable diagnostic messages to stderr.
If the flag is set, restrict these messages to errors.
-V, --version
Prints version information
SUBCOMMANDS:
bundle Bundle module and dependencies into single file
cache Cache the dependencies
completions Generate shell completions
doc Show documentation for a module
eval Eval script
fmt Format source files
help Prints this message or the help of the given subcommand(s)
info Show info about cache or info related to source file
install Install script as an executable
repl Read Eval Print Loop
run Run a program given a filename or url to the module
test Run tests
types Print runtime TypeScript declarations
upgrade Upgrade deno executable to newest version
ENVIRONMENT VARIABLES:
DENO_DIR Set deno's base directory (defaults to $HOME/.deno) DENO_INSTALL_ROOT Set deno install's output directory
(defaults to $HOME/.deno/bin)
NO_COLOR Set to disable color
HTTP_PROXY Proxy address for HTTP requests
(module downloads, fetch)
HTTPS_PROXY Same but for HTTPS
Copy the code
Command line options
--allow-env Allows environment access --allow-hrtime allows high precision time measurement --allow-net = allows network access --allow-plugin allows plug-in loading --allow-read = Allows file system read access --allow-run Allows child processes to run --allow-write = Allows file system write access --allow-all Allows all permissions (same as -a)Copy the code
(5) Deno code examples
Deno. land/ STD /example…
(6) Standard library
- Archive: tar archive tool
- async async utilties
- Async: async tool
- Bytes: Assist for manipulating byte fragments
- Datetime: date/time resolution
- Encoding: Encoding/decoding of various formats
- Flags: parses command line flags
- FMT: Format and print
- Fs: file system API
- Hash: encrypted library
- HTTP: indicates the HTTP server
- IO: I/O library
- Log: log utility
- Mime: Supports multipart data
- Node: node.js compatibility layer
- Path: indicates the path operation
- Ws: web sockets
A simple example of full stack application
Build REST apis with Oak. Oak was inspired by the popular Node.js middleware Koa.
The API built is very simple. Our server will store a list of data in memory with a name and password email.
- Add new data
- List the data
- Gets the details of a particular data
- Removes a data item from the list
- Update the age of the data
For the convenience of building a common and flexible application template in the future, we will do some Settings in advance
(I) The basic contents of the project are as follows
.
|-- config
| |-- db.ts
| |-- env.ts
| `-- talent-deno-test.json
|-- controllers
| |-- auth.ts
| |-- games.mysql.ts
| `-- user.ts
|-- deno.json
|-- deps.ts
|-- docs
| |-- index.md
| `-- tutorial.md
|-- drun.json
|-- helpers
| |-- between.ts
| |-- render.ts
| `-- request.ts
|-- middleware
| |-- authorize.ts
| |-- error.ts
| |-- logger.ts
| |-- state.ts
| `-- timer.ts
|-- models
| |-- GameModel.ts
| `-- UserModel.ts
|-- pages
| |-- app.tsx
| |-- form.tsx
| `-- list.tsx
|-- readme.md
|-- routes
| |-- auth.tsx
| |-- game.ts
| `-- home.tsx
|-- server.ts
|-- services
| |-- crud.sql.ts
| `-- db.sql.ts
|-- testdeps.ts
|-- tests
| |-- model_test.ts
| `-- oak.test.ts
|-- tsconfig.json
`-- types.ts
Copy the code
(2) Establish project folders
mkdir deno-project
cd deno-project
touch deps.ts
deno cache deps.ts
Copy the code
(3) Centralized management dependency
Our deps. Ts file, similar to package.json under Node, allows us to do some dependency management
// server
export {
Application,
Router,
Status,
isHttpError,
} from "https://deno.land/x/oak/mod.ts";
export { oakCors } from "https://deno.land/x/cors/mod.ts";
// React
export { default as React } from "https://dev.jspm.io/[email protected]";
export { default as ReactDOMServer } from "https://dev.jspm.io/[email protected]/server";
export { default as ReactRouter } from "https://dev.jspm.io/react-router";
export { default as ReactHookForm } from "https://dev.jspm.io/react-hook-form";
// ORM
export {
dso,
Client,
Where,
Model,
BaseModel,
FieldType,
Field,
} from "https://deno.land/x/[email protected]/mod.ts";
// services
export {
cron,
daily,
monthly,
weekly,
} from "https://deno.land/x/deno_cron/cron.ts";
// Helpers
export { config } from "https://deno.land/x/[email protected]/mod.ts";
export { slugify } from "https://deno.land/x/[email protected]/mod.ts";
export { makeJwt } from "https://deno.land/x/[email protected]/create.ts";
export { validateJwt } from "https://deno.land/x/[email protected]/validate.ts";
export { hash, compare } from "https://deno.land/x/[email protected]/mod.ts";
export { v4 } from "https://deno.land/std/uuid/mod.ts";
export { program, Lizard } from "https://deno.land/x/denomander/mod.ts";
export { readJsonSync, writeJsonSync } from "https://deno.land/std/fs/mod.ts";
Copy the code
Tip: If you want to cache various dependencies ahead of time
deno cache --unstable deps.ts
Copy the code
Create env.ts
mkdir config
touch config/env.ts
touch .env
Copy the code
- Environment profile
config/env.ts
import { config } from ".. /deps.ts";
const env = config();
export default env;
Copy the code
- Environment configuration data is written in
.env
In the file
HOST=http://0.0.0.0
PORT=8000
TOKEN_SECRET=20090909
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=monitor
DB_USERNAME=monitor
DB_PASSWORD=20090909
Copy the code
You can then import environment variables using the following methods
import env from './config/env.ts';
env['HOST']
Copy the code
Create server.ts file
Create a server.ts file in the project root directory
Import Application and Router objects from Oak:
Then we get the environment variables PORT and HOST:
Run and listen
import { Application, oakCors } from "./deps.ts";
import env from "./config/env.ts";
// Routes
import homeRouter from "./routes/home.tsx";
import authRouter from "./routes/auth.tsx";
const host = env["HOST"];
const port = parseInt(env["PORT"]);
// Configure Application
export const app = new Application();
// Builtin middleware
app.use(oakCors()); // Enable CORS for All Routes
app.use(homeRouter.routes())
.use(authRouter.routes());
app.use(homeRouter.allowedMethods())
.use(authRouter.allowedMethods());
// Bootstrap Application
console.log(`Server running on ${host}:${port}`);
await app.listen({ port });
Copy the code
Create a tsconfig.json file in the project root directory
Because our project will use ReactJS and decorators, enable both experimentalDecorators and JSX
{
"compilerOptions": {
"jsx": "react"."allowJs": false."emitDecoratorMetadata": true."experimentalDecorators": true."module": "esnext",}}Copy the code
(6) Start the application program
deno run -A --unstable -c tsconfig.json server.ts
Copy the code
Deno will then download the dependencies and run our program automatically
(7) Create a router
User authenticated route routes/auth.ts
import { Router } from '.. /deps.ts';
import { register, login } from ".. /controllers/auth.ts";
import { getUsers, getUser, addUser, updateUser, deleteUser } from ".. /controllers/user.ts";
const router = new Router();
router.post("/auth/register", register)
.post("/auth/login", login);
router.get("/api/v1/users", getUsers)
.get("/api/v1/users", getUser)
.post("/api/v1/users", register)
.put("/api/v1/users", updateUser)
.delete("/api/v1/users", deleteUser);
export default router;
Copy the code
Our API interface is the background server Settings
The /auth/register interface implements the registration function. The auth/login interface implements the login function
(8) Add controller, API call function:
User validated controllers/auth.ts
The register method is called when a user sends a POST request to /auth/register
According to Oak’s design, the controller’s corresponding method is an asynchronous function whose parameter CTX is of the following type
{
request: any;
response: any;
params: any;
}
Copy the code
Note that we use const body = await request.body() to get the content of the network request body, and the value is passed as JSON.
Data processing results are directly used to modify response objects, such as status, data, type
import { Status, compare, makeJwt, hash, config } from ".. /deps.ts";
import env from ".. /config/env.ts";
import { findRecord, addRecord } from ".. /services/crud.sql.ts";
import { userModel } from ".. /services/db.sql.ts";
export async function register(ctx: any) {
const body = await ctx.request.body();
console.log(body);
// FIXEM: password is hashed and needs long string, over 100
let checkId = await findRecord(userModel, { name: body.value.name });
if(! checkId) {const password = await hash(body.value.password);
const user = await addRecord(userModel, {
name: body.value.name,
email: body.value.email,
password,
});
ctx.response.status = Status.Created;
ctx.response.type = "json";
ctx.response.body = {
status: "success",
message: `user registered in database`,
data: {
user,
},
};
} else {
ctx.throw(Status.BadRequest, "User name exits!"); }}export async function login(ctx: any) {
const body = await ctx.request.body();
// Find record with name
let user: any = await findRecord(userModel, { name: body.value.name });
if(! user) { ctx.throw(Status.UnprocessableEntity,"Wrong Email Address!");
} else if (await compare(body.value.password, user.password)) {
const token = makeJwt(
{
header: { alg: "HS256", typ: "JWT" },
payload: { id: user.id, name: user.name, email: user.email },
key: env["TOKEN_SECRET"],},); ctx.response.status = Status.OK; ctx.response.type ="json";
ctx.response.body = {
status: "success",
message: `Logged in with ${body.value.email}`,
data: { accessToken: token },
};
// set redirect
} else {
ctx.throw(Status.Unauthorized, "Wrong Password!"); }}Copy the code
For maintenance purposes, we abstract the background operations of the database into services, such as calling addRecord from the Register method, which is defined in a separate crud.sql.ts
(9) Implement the method of adding, deleting, modifying and checking
Defined in the services/crud.sql.ts file
1. Query data method:
import {
Where,
BaseModel,
} from ".. /deps.ts";
// Grub Options
export async function findAllRecord(model: BaseModel) {
const records = await model.findAll(Where.expr("id > 0"));
console.log("Found user by id:", records);
return records;
}
export async function findRecord(model: BaseModel, query: any) {
let record;
if (query.id) {
record = await model.findById(query.id);
} else {
record = await model.findOne(Where.from(query));
}
console.log("Found user by id:", record);
return record;
}
Copy the code
2. New data method:
Adding data is very simple. Here we take ORM Model objects as parameters and call Model methods to perform database operations.
import {
Where,
BaseModel,
} from ".. /deps.ts";
export async function addRecord(model: BaseModel, data: any) {
const id = await model.insert(data);
console.log("New user with id:", id);
return id;
}
Copy the code
3. Update and delete methods:
Delete and query, primarily using the Query parameter, is a JSON object that must contain the ID field as a unique identifier
export async function updateRecord(model: BaseModel, query: any) {
const records = await model.update(query, Where.from({ id: query.id }));
console.log("Update user with id:", records);
return records;
}
export async function deleteRecord(model: BaseModel, query: any) {
const count = await model.delete(Where.from(query));
console.log(`${count} record deleted`);
return count;
}
Copy the code
Mysql and ORM support
We use the DSO module to provide ORM support, although you can use other similar modules such as denodb or Cotton
But because deno is still in continuous development, there are many database pits, said to be classes.
For example, when defining a Model, if the password needs to be hashed, this field is very long. Set enough field length in the Model, otherwise the server will report an error, and cannot check at all!
For example, when using denodb, there are often inexplicable errors such as compile Error or file Not found. Hopefully, these problems will be eliminated as the version improves.
1. The Model is a Model
Our user model contains three fields: name, password and email
import {
BaseModel,
Field,
FieldType,
Model,
} from ".. /deps.ts";
// Define a database model
@Model("users")
export class UserModel extends BaseModel {
@Field({
type: FieldType.INT,
primary: true,
length: 11,
autoIncrement: true, }) id! :number;
@Field({ type: FieldType.STRING, length: 30, notNull: true}) name! :string;
// FIXEM: password is hashed and needs long string, over 100
@Field({ type: FieldType.STRING, length: 100, notNull: true}) password! :string;
@Field({ type: FieldType.STRING, length: 30}) email? :string;
}
Copy the code
2. Connect to the database
Dso is an easy-to-use ORM project that takes only three steps to initialize
-
Use the dso.define data table structure, whose parameters are Model
-
Start dso.connect for database connection
-
Use dso.sync for synchronization, and if there is no corresponding table, it will be created automatically. Note that passing true will reset the database, deleting all existing data
The contents of the services/db.sql.ts file are as follows:
import {
dso,
Client,
} from ".. /deps.ts";
import { mysqlOption } from ".. /config/db.ts";
import { UserModel } from ".. /models/UserModel.ts";
import { GameModel } from ".. /models/GameModel.ts";
export const userModel = dso.define(UserModel);
export const gameModel = dso.define(GameModel);
export const client: Client = await dso.connect(mysqlOption);
export async function initDb() {
await dso.sync(false);
}
Copy the code
3. Configure the database connection
config/db.ts
import env from "./env.ts";
export const mysqlOption = {
hostname: env["DB_HOST"],
port: parseInt(env["DB_PORT"]),
username: env["DB_USERNAME"],
password: env["DB_PASSWORD"],
db: env["DB_DATABASE"]}Copy the code
(11) Introduction of password authentication
As you can see, we use the compare method in the login method in controllers/auth.ts to verify the plaintext password in the network request against the hash password obtained by the database and use makeJwt to generate the new token
Controllers /auth.ts
export async function login(ctx: any) {
const body = await ctx.request.body();
// Find record with name
let user: any = await findRecord(userModel, { name: body.value.name });
if(! user) { ctx.throw(Status.UnprocessableEntity,"Wrong Email Address!");
} else if (await compare(body.value.password, user.password)) {
const token = makeJwt(
{
header: { alg: "HS256", typ: "JWT" },
payload: { id: user.id, name: user.name, email: user.email },
key: env["TOKEN_SECRET"],},); ctx.response.status = Status.OK; ctx.response.type ="json";
ctx.response.body = {
status: "success",
message: `Logged in with ${body.value.email}`,
data: { accessToken: token },
};
// set redirect
} else {
ctx.throw(Status.Unauthorized, "Wrong Password!"); }}Copy the code
Middelwares/Authorize defines a middleware, using validateJwt to implement JWT validation
import { Status, validateJwt, config } from ".. /deps.ts";
const env = config();
export default async (ctx: any, next: any) = > {// FIXED: Check authorization
const authHeader = ctx.request.headers.get("authorization");
if(! authHeader) { ctx.throw(Status.Unauthorized); }else {
const requestToken = authHeader.split("") [1];
try {
const jwt: any = await validateJwt(requestToken, env["TOKEN_SECRET"]);
ctx.request.user = jwt.payload
await next();
} catch(err) { ctx.throw(Status.Unauthorized); }}};Copy the code
I used the Chrome Talent Rest plug-in for Talent to test
Third, client trial
Reactjs support
Adding ReactJS support is a bit more difficult, mainly the coordination between the server and the client, the specific principle is not well understood by the author, please refer to the following articles and videos
define 2 routes: one to serve a simple HTML page containing our rendered app, and another browser.js route to server our app’s code so we can [hydrate] the React application on the client.
Simply put, two routes need to be defined
The first function is to render the HTML page, including the app itself
The second is to provide the browser.js script, which provides dynamic functionality for our app
(2) Set App components
The main page needs to be rendered with Oak routing
Here we need to use the React -doom-server renderString. For better implementation, I use the htmlWrapper helper function to return the component content we need to be able to use on the server.
(3) Route setting
The following information is displayed in the routes/home.ts command:
/ / @ deno - types = "https://deno.land/x/types/react/v16.13.1/react.d.ts"
/ / @ deno - types = "https://deno.land/x/types/react-dom/v16.13.1/server.d.ts"
import { React, Router, ReactDOMServer, ReactRouter } from '.. /deps.ts';
import App, { AppWithRouter } from '.. /pages/app.tsx';
import LoginComponent from '.. /pages/form.tsx';
import ListComponent from '.. /pages/list.tsx';
import { htmlWrapper, jsMultiWrapper } from '.. /helpers/render.ts';
const { StaticRouter, BrowserRouter } = ReactRouter;
// Import client reactjs
const browserBundlePath = "/browser.js";
const router = new Router();
router.get("/".(ctx: any) = > {
// And then on the server we’ll use the analogous, but stateless StaticRouter component:
const body = htmlWrapper(App);
ctx.response.type = 'text/html';
ctx.response.body = body;
});
// Client render App
router.get(browserBundlePath, ({ response }: { response: any}) = > {
// On the client-side, let’s simply wrap our App component with React Router’s BrowserRouter component:
const js = jsMultiWrapper([
{
name: 'App',
component: App
},
{
name: 'LoginComponent',
component: LoginComponent
},
{
name: 'ListComponent',
component: ListComponent
}
]);
response.type = 'application/javascript';
response.body = js;
});
export default router;
Copy the code
Use the helper for the actual rendering
The helper function is realized as follows:
-
Introduce a series of libraries from under dev.jspm.io
-
Import a series of components (although direct imports will report an error because the related components are not defined in the script file. Importing each component one by one is not practical, so you need to wrap it up and define each component as a constant by name.)
-
Browser.js is rendered with reactdom.hydrate (react.createElement (App) to support building dynamic functionality
-
Render the component using (ReactDOMServer as any).renderToString(Component)
Helpers/render. Ts as follows:
/ / @ deno - types = "https://deno.land/x/types/react-dom/v16.13.1/server.d.ts"
import { ReactDOMServer, ReactRouter } from '.. /deps.ts';
const { StaticRouter, BrowserRouter } = ReactRouter;
const jspms = [
'the import the React from "https://dev.jspm.io/[email protected]" ".'the import ReactDOM from "https://dev.jspm.io/[email protected]" ".'import ReactRouter from "https://dev.jspm.io/react-router"'.'import ReactHookForm from "https://dev.jspm.io/react-hook-form"'
]
const libs = jspms.join('; \n');
// Import client reactjs
export const htmlWrapper = (component: any) = > {
const browserBundlePath = "/browser.js";
const html =
`<html><head><script type="module" src="${browserBundlePath}"> < / script > < link href =" https://unpkg.com/tailwindcss@ ^ 1.0 / dist/tailwind. Min. CSS "rel =" stylesheet "> < / head > < body > < div id="app">${ (ReactDOMServer as any).renderToString(component) }</div></body></html>`;
const body = new TextEncoder().encode(html);
return body
};
export const jsMultiWrapper = (components: { name: string; component: any} []) = > {
// On the client-side, let’s simply wrap our App component with React Router’s BrowserRouter component:
const componentLines: string = components.reduce((pre: any, cur: any) = > {
const line = `const ${cur.name} = ${cur.component}; `
return pre + '\n' + line;
}, ' ')
const js =
`${libs}; \n${componentLines}; \nReactDOM.hydrate(React.createElement(App), document.getElementById("app")); `;
return js;
};
Copy the code
(4) Pages and components
1. The App components
The main page pages/app.tsx contains the following contents:
/ / @ deno - types = "https://deno.land/x/types/react/v16.13.1/react.d.ts" import {React} from ".. /deps.ts"; import ListComponent from "./list.tsx"; import LoginComponent from "./form.tsx"; declare global { namespace JSX { interface IntrinsicElements { button: any; div: any; h1: any; p: any; a: any; ul: any; li: any; span: any; form: any; label: any; input: any; } } } const App = (props: any) => { return ( <div class="flex"> <div class="w-2/5"> <LoginComponent /> </div> <div class="w-3/5"> <ListComponent /> </div> </div> ); }; export default App;Copy the code
2. LoginComponent components
This component implements the functionality of the form
The pages/form.tsx page is as follows:
Here we try to add some new things, such as tailwindCSS and react-hook-form, to see if they can be combined
/ / @ deno - types = "https://deno.land/x/types/react/v16.13.1/react.d.ts" import {React, ReactHookForm} from ".. /deps.ts"; import env from ".. /config/env.ts"; const LoginComponent = () => { const { register, handleSubmit } = (ReactHookForm as any).useForm(); const onSubmit = async (data: any) => { console.log(data); // Try login const response: any = await fetch("/auth/login", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); console.log(response); // if user exists try login if (response.status ! == 200) { const response: any = await fetch("/auth/register", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); }}; return ( <div class="w-full pl-10 pt-50"> <form onSubmit={handleSubmit(onSubmit)} class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" > <div class="mb-4"> <label class="block text-gray-700 text-sm font-bold mb-2" for="name" > Username </label> <input name="name" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" type="text" ref={register} /> </div> <div class="mb-4"> <label class="block text-gray-700 text-sm font-bold mb-2" for="email" > Email </label> <input name="email" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" type="text" ref={register} /> </div> <div class="mb-6"> <label class="block text-gray-700 text-sm font-bold mb-2" for="password" > Password </label> <input class="shadow appearance-none border border-red-500 rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline" name="password" type="password" ref={register} /> <p class="text-red-500 text-xs italic">Please choose a password.</p> </div> <div class="flex items-center justify-between"> <input class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit" /> <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" href="#" > Forgot Password? </a> </div> </form> <p class="text-center text-gray-500 text-xs"> © 2020 Acme Corp. All rights reserved. </p> </div> ); }; export default LoginComponent;Copy the code
Access the root directory and display our React App. Add and remove functions work fine! That’s great!
Open the inspector in your browser, open browser.js in the Source panel, and the final code looks like this
4. Debug Deno
Deno supports V8 Inspector Protocol. You can debug Deno programs using Chrome Devtools or another client that supports the protocol, such as VSCode. To enable debugging, run Deno with the –inspect or –inspect-brk options, which are described below:
–inspect=HOST:PORT activate inspector on host:port (default: 127.0.0.1:9229)
–inspect-brk=HOST:PORT activate inspector on host:port and break at start of user script
The copy code –inspect option allows the debugger to connect at any point in time, while the –inspect-brk option waits for the debugger to connect and pauses execution at the first line of code.
Chrome Devtools
Let’s use Chrome Developer tools to debug
Pause execution at the first line of code using the –inspect-brk option.
deno run --inspect-brk -A server.ts
Copy the code
Copy the code to open Chrome ://inspect, click inspect next to Target
For more detailed debugging instructions, visit the deno.land/manual address.
(2) VSCode
Deno can be debugged in VSCode. Official support for plug-ins is being developed
The configuration in launch.json is as follows
{
"version": "0.2.0"."configurations": [{"name": "Deno"."type": "node"."request": "launch"."cwd": "${workspaceFolder}"."runtimeExecutable": "deno"."runtimeArgs": ["run"."--inspect-brk"."-A"."<entry_point>"]."port": 9229}}]Copy the code
The source address
Github address: github.com/linuxing3/d…
More Resources
-
Nguyen other web logs of www.ruanyifeng.com/blog/2020/0…
-
Deno’s official website, deno.land
-
API documentation doc.deno.land and deno.land/typedoc
-
Awesome – deno github.com/denolib/awe…
-
The kosi www.axihe.com/edu/deno/ho…
-
Deno中文 书 包 nugine.github. IO /deno-manual…