惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Jina AI
Jina AI
月光博客
月光博客
F
Fortinet All Blogs
Stack Overflow Blog
Stack Overflow Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
博客园 - 司徒正美
P
Proofpoint News Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
M
MIT News - Artificial intelligence
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research
S
SegmentFault 最新的问题
博客园_首页
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
L
LangChain Blog
博客园 - 聂微东
G
Google Developers Blog
博客园 - Franky

Deno

Deno 2.8 | Deno Claw Patrol: an open-source security firewall for agents | Deno Fresh 2.3: Zero JS by default, View Transitions, and Temporal support | Deno Deno 2.7: Temporal API, Windows ARM, and npm overrides | Deno Build a dinosaur runner game with Deno, pt. 6 | Deno Build a dinosaur runner game with Deno, pt. 5 | Deno Deno Deploy is Generally Available | Deno Introducing Deno Sandbox | Deno Build a dinosaur runner game with Deno, pt. 4 | Deno Build a dinosaur runner game with Deno, pt. 3 | Deno Build a dinosaur runner game with Deno, pt. 2 | Deno React / Next.js Denial-of-Service Vulnerability: Deno Deploy users protected | Deno Deno 2.6: dx is the new npx | Deno Build a dinosaur runner game with Deno, pt. 1 | Deno React Server Functions / Next.js Vulnerability: Deno Deploy users protected | Deno My highlights from the new Deno Deploy | Deno Deno's Other Open Source Projects | Deno How Deno protects against npm exploits | Deno Help Us Raise $200k to Free JavaScript from Oracle | Deno Deno 2.5: Permissions in the config file | Deno Fresh 2.0 Graduates to Beta, Adds Vite Support | Deno Deno 2.4: deno bundle is back | Deno JavaScript™ Trademark Update | Deno What's coming to JavaScript | Deno A brief history of JavaScript | Deno Reports of Deno's Demise Have Been Greatly Exaggerated | Deno An Update on Fresh | Deno How Plaid migrated 100 services to a new database platform 5x faster with Deno | Deno Deno 2.3: Improved deno compile, local npm packages, and more | Deno Add JSR packages with pnpm and Yarn | Deno
Build Apps in Deno with Frameworks such as React, Vue, Ex...
Andy Jiang · 2022-11-16 · via Deno

There is no shortage of frameworks to build websites and apps in JavaScript. (In fact, as you are reading this, a new one just came out.) Since npm has become the main distribution platform for many things JavaScript, most require npm to use.

With Deno 1.28, you can now build with these JavaScript frameworks, such as Express, React, Vue, and more.

This blog post will show you how to get started with these JavaScript frameworks in Deno:

  • Express
  • React
  • Vue

Check out our Manual for more How To guides on using JavaScript frameworks with npm.

Write less code

Building with these frameworks will be faster, require less configuration, and use less boilerplate with Deno:

  • spend less time evaluating and building your own tools—Deno ships with a robust toolchain, which includes deno test, deno lint, deno fmt and more.
  • no package.json, .tsconfig, or node_modules subdirectory (by default), which can distract you from the code that matters
  • no separate npm install step—modules are cached once in a special global directory

In the examples below, we’ll show how easy it is to get started using npm with Deno.

Express

Express is a popular web framework known for being simple and unopinionated with a large ecosystem of middleware.

Let’s create a simple API using Express and Deno.

View source here.

Create main.ts

Let’s create main.ts:

touch main.ts

In main.ts, let’s create a simple server:


import express from "npm:express@4.18.2";

const app = express();

app.get("/", (req, res) => {
  res.send("Welcome to the Dinosaur API!");
});

app.listen(8000);

Let’s run this server:

deno run --allow-net main.ts

And point our browser to localhost:8000. You should see:

Welcome to the Dinosaur API!

Add data and routes

The next step here is to add some data. We’ll use this Dinosaur data that we found from this article. Feel free to copy it from here.

Let’s create data.json:

touch data.json

And paste in the dinosaur data.

Next, let’s import that data into main.ts. Let’s add this line at the top of the file:

import data from "./data.json" with { type: "json" };

Then, we can create the routes to access that data. To keep it simple, let’s just define GET handlers for /api/ and /api/:dinosaur. Add the below after the const app = express(); line:

app.get("/", (req, res) => {
  res.send("Welcome to the Dinosaur API!");
});

app.get("/api", (req, res) => {
  res.send(data);
});

app.get("/api/:dinosaur", (req, res) => {
  if (req?.params?.dinosaur) {
    const filtered = data.filter((item) => {
      return item["name"].toLowerCase() === req.params.dinosaur.toLowerCase();
    });
    if (filtered.length === 0) {
      return res.send("No dinosaurs found.");
    } else {
      return res.send(filtered[0]);
    }
  }
});

app.listen(8000);

Let’s run the server with deno run --allow-net main.ts and check out localhost:8000/api. You should see a list of dinosaurs:

[
  {
    "name": "Aardonyx",
    "description": "An early stage in the evolution of sauropods."
  },
  {
    "name": "Abelisaurus",
    "description": "\"Abel's lizard\" has been reconstructed from a single skull."
  },
  {
    "name": "Abrictosaurus",
    "description": "An early relative of Heterodontosaurus."
  },
...

And when we go to localhost:8000/api/aardonyx:

{
  "name": "Aardonyx",
  "description": "An early stage in the evolution of sauropods."
}

Awesome!

React

While Express is great for APIs and services, React is meant for user interfaces. It popularized a declarative approach towards designing interfaces, with a reactive data model. And due to its popularity, it’s not surprising that it’s the most requested framework when it comes to building web apps with Deno.

Let’s create an app that’ll display a list of dinosaurs. When you click on one, it’ll take you to a dinosaur page with more details.

View the source or follow the video guide.

Let’s use Vite to quickly scaffold a Deno and React app:

deno run --allow-read --allow-write --allow-env npm:create-vite-extra@latest

We’ll name our project “dinosaur-react-app”. Then, cd into the newly created project folder.

Add a backend

The next step is to add a backend API. We’ll create a very simple API that returns information about dinosaurs.

In the directory, let’s create an api folder. In that folder, we’ll create a main.ts file, which will run the server, and a data.json, which is the hard coded data.

mkdir api && touch api/data.json && touch api/main.ts

Copy and paste this json file into your api/data.json.

Then, let’s update api/main.ts:

import { Application, Router } from "https://deno.land/x/oak@v11.1.0/mod.ts";
import { oakCors } from "https://deno.land/x/cors@v1.2.2/mod.ts";
import data from "./data.json" with { type: "json" };

const router = new Router();
router
  .get("/", (context) => {
    context.response.body = "Welcome to dinosaur API!";
  })
  .get("/api", (context) => {
    context.response.body = data;
  })
  .get("/api/:dinosaur", (context) => {
    if (context?.params?.dinosaur) {
      const filtered = data.filter((item) =>
        item["name"].toLowerCase() === context.params.dinosaur.toLowerCase()
      );
      if (filtered.length === 0) {
        context.response.body = "No dinosaurs found.";
      } else {
        context.response.body = filtered[0];
      }
    }
  });

const app = new Application();
app.use(oakCors()); 
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

This is a very simple API server using oak that will return dinosaur information based on the route. Let’s start the API server:

deno run --allow-env --allow-net api/main.ts

If we go to localhost:8000, we see:

json response of dinosaurs

Lookin’ good so far.

Add a router

Our app will have two routes: / and /:dinosaur.

We’ll use react-router-dom for our routing logic. Let’s add that to our dependencies in vite.config.mjs:

import { defineConfig } from "npm:vite@^3.1.3";
import react from "npm:@vitejs/plugin-react@^2.1";

import "npm:react@^18.2";
import "npm:react-dom/client@^18.2";
import "npm:react-router-dom@^6.4"; 


export default defineConfig({
  plugins: [react()],
});

Once we add the dependencies there, we can import them without npm: specifier throughout our React app.

Next, let’s go to src/App.jsx and add our routing logic:

import React from "react";
import {
  BrowserRouter as Router,
  Navigate,
  Route,
  Routes,
} from "react-router-dom";
import Index from "./pages/Index.jsx";
import Dinosaur from "./pages/Dinosaur.jsx";

export default function App(props) {
  return (
    <Router>
      <Routes>
        <Route exact path="/" element={<Index />} />
        <Route exact path="/:dinosaur" element={<Dinosaur />} />
        <Route path="*" element={<Navigate to="/" />} />
      </Routes>
    </Router>
  );
}

Next, let’s add the <Index> and <Dinosaur> pages.

Add pages

There will be two pages in this app:

  • src/pages/Index.jsx: our index page, which lists all of the dinosaurs
  • src/pages/Dinosaur.jsx: our dinosaur page, which shows details of the dinosaur

We’ll create a src/pages folder and create the .jsx files:

mkdir src/pages && touch src/pages/Index.jsx src/pages/Dinosaur.jsx

Let’s start with <Index>. This page will fetch at localhost:8000/api and render that through JSX.

import React, { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";

const Index = () => {
  const [dinos, setDinos] = useState([]);
  useEffect(() => {
    fetch(`http://localhost:8000/api/`)
      .then(async (res) => await res.json())
      .then((json) => setDinos(json));
  }, []);

  return (
    <div>
      <h1>Welcome to the Dinosaur app</h1>
      <p>
        Click on a dinosaur below to learn more.
      </p>
      <div>
        {dinos.map((dino) => {
          return (
            <div>
              <Link to={`/${dino.name.toLowerCase()}`}>{dino.name}</Link>
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default Index;

Next, in <Dinosaur>, we’ll do the same except for localhost:8000/api/${dinosaur}:

import React, { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";

const Dinosaur = () => {
  const { dinosaur } = useParams();
  const [dino, setDino] = useState({});
  useEffect(() => {
    fetch(`http://localhost:8000/api/${dinosaur}`)
      .then(async (res) => await res.json())
      .then((json) => setDino(json));
  }, []);

  return (
    <div>
      <h1>{dino.name}</h1>
      <p>
        {dino.description}
      </p>
      <Link to="/">See all</Link>
    </div>
  );
};

export default Dinosaur;

Let’s start the React app:

deno task start

And click through the app:

demo of the app

Success!

For more information using React, please refer to their documentation.

Vue

Vue is a progressive front-end JavaScript framework, built for performance and versatility.

Let’s create the exact same app we did with React, but now in Vue.

View the source or follow the video guide.

We’ll use Vite to scaffold our Vue app:

deno run --allow-read --allow-write --allow-env npm:create-vite-extra@latest

Name your project, then select “deno-vue”.

Then, cd into your new project and run:

deno task dev

You should now be able to view your default Deno and Vue app in your browser:

default vue app

Add a backend

The next step is to add a backend API. We’ll create a very simple API that returns information about dinosaurs.

In the directory, let’s create an api folder. In that folder, we’ll create a main.ts file, which will run the server, and a data.json, which is the hard coded data.

mkdir api && touch api/data.json && touch api/main.ts

Copy and paste this json file into your api/data.json.

Then, let’s update api/main.ts:

import { Application, Router } from "https://deno.land/x/oak@v11.1.0/mod.ts";
import { oakCors } from "https://deno.land/x/cors@v1.2.2/mod.ts";
import data from "./data.json" with { type: "json" };

const router = new Router();
router
  .get("/", (context) => {
    context.response.body = "Welcome to dinosaur API!";
  })
  .get("/api", (context) => {
    context.response.body = data;
  })
  .get("/api/:dinosaur", (context) => {
    if (context?.params?.dinosaur) {
      const found = data.find((item) =>
        item.name.toLowerCase() === context.params.dinosaur.toLowerCase()
      );
      if (found) {
        context.response.body = found;
      } else {
        context.response.body = "No dinosaurs found.";
      }
    }
  });

const app = new Application();
app.use(oakCors()); 
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });

This is a very simple API server using oak that will return dinosaur information based on the route. Let’s start the API server:

deno run --allow-env --allow-net api/main.ts

If we go to localhost:8000/api, we see:

json response of dinosaurs

So far, so good.

Add Vue components

Let’s update src/components. We’ll add the following files:

  • HomePage.vue, the component for the home page
  • Dinosaurs.vue, the component that lists all dinosaur names as anchor links, and
  • Dinosaur.vue, the component that shows an individual dinosaur’s name and description
touch src/components/HomePage.vue src/components/Dinosaurs.vue src/components/Dinosaur.vue

Before we create the components, let’s add some state management.

Maintain state with store

In order to maintain state across our <Dinosaur> and <Dinosaurs> components, we’ll use Vue store. Note for more complex state management, check out the Vue-endorsed Pinia library.

Create a src/store.js file:

touch src/store.js

And in it, let’s add:

import { reactive } from "vue";

export const store = reactive({
  dinosaur: {},
  setDinosaur(name, description) {
    this.dinosaur.name = name;
    this.dinosaur.description = description;
  },
});

We’ll import store into both Dinosaurs.vue and Dinosaur.vue to set and retrieve dinosaur name and description.

Update Vue components

In Dinosaurs.vue, we’ll do three things:

  • send a GET request to our API and return that as dinosaurs
  • iterate through dinosaurs and render each dinosaur in <router-link> that points to the <Dinosaur> component
  • add store.setDinosaur() to @click on each dinosaur, which will set the store

Here is the complete code below:

<script>
import { ref } from 'vue'
import { store } from '../store.js'
export default ({
  async setup() {
    const res = await fetch("http://localhost:8000/api")
    const dinosaurs = await res.json();
    return {
      dinosaurs
    }
  },
  data() {
    return {
      store
    }
  }
})
</script>

<template>
  <div class="container">
    <div v-for="dinosaur in dinosaurs" class="dinosaur-wrapper">
      <span class="dinosaur">
        <router-link :to="{ name: 'Dinosaur', params: { dinosaur: `${dinosaur.name.toLowerCase()}` }}">
          <span @click="store.setDinosaur(dinosaur.name, dinosaur.description)">
            {{dinosaur.name}}
          </span>
        </router-link>
      </span>
    </div>
  </div>
</template>

<style scoped>
.dinosaur {
}
.dinosaur-wrapper {
  display: inline-block;
  margin: 0.15rem 1rem;
  padding: 0.15rem 1rem;
}
.container {
  text-align: left;
}
</style>

In Dinosaur.vue, we’ll add:

  • importing store
  • rendering store.dinosaur in the HTML
<script>
import { store } from '../store.js';
export default {
  data() {
    return {
      store
    }
  }
}
</script>

<template>
  Name: {{ store.dinosaur.name }}
  <br />
  Description: {{ store.dinosaur.description }}
</template>

Next, we’ll update HomePage.vue. Since the Dinosaurs component needs to fetch the data from the API, we’ll use <Suspense>, which manages async dependencies in a component tree.

<script>
import { ref } from 'vue'
import Dinosaurs from './Dinosaurs.vue'
export default {
  components: {
    Dinosaurs
  }
}
</script>

<template>
  <Suspense>
    <template #default>
      <Dinosaurs />
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>

  <p>
    Check out
    <a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
      >create-vue</a
    >, the official Vue + Vite starter
  </p>
  <p class="read-the-docs">Learn more about using Deno and Vite.</p>
</template>

<style scoped>
.read-the-docs {
  color: #888;
}
</style>

Tying it all together, let’s update src/App.vue:

<template>
  <router-view />
</template>;

Add routing

You’ll notice that we have used <router-link> and <router-view>. These components are part of the vue-router library, which we’ll have to setup and configure in another file.

First, let’s import vue-router in our vite.config.mjs file:

import { defineConfig } from "npm:vite@^3.1.3";
import vue from "npm:@vitejs/plugin-vue@^3.2.39";

import "npm:vue@^3.2.39";
import "npm:vue-router@4";


export default defineConfig({
  plugins: [vue()],
});

Next, let’s create a folder named router. In it, let’s create index.ts:

mkdir router && touch router/index.ts

In router/index.ts, we’ll create router, which contains information about each route and their component, and export it. For more information on using vue-router, check out their guide.

import { createRouter, createWebHistory } from "vue-router";
import HomePage from "../components/HomePage.vue";
import Dinosaur from "../components/Dinosaur.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: HomePage,
  },
  {
    path: "/:dinosaur",
    name: "Dinosaur",
    component: Dinosaur,
    props: true,
  },
];

const router = createRouter({
  history: createWebHistory("/"),
  routes,
});

export default router;

Next, in our src/main.ts file, which contains all of the logic for the frontend app, we’ll have to import and use router:

import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import router from "./router/index.ts";

const app = createApp(App);
app.use(router);
app.mount("#app");

Let’s run it and see what we get so far:

Clicking on a dinosaur to get to an individual dinosaur page

Awesome!

What’s next?

Hopefully, these examples showed how easy it is to get up and running with Deno and a JavaScript web framework. They are also starting points for building an app. From there, you could add proper data persistence, add additional routes, implement authentication, etc. Lastly, we plan to continue adding How To guides in our Manual.

We’re also excited to announce that we are hosting a livestream on our YouTube channel tomorrow, Thursday, November 17th, at 9am PT, where we’ll

  • discuss using npm with Deno,
  • answer any questions from the live chat or our Discord, and
  • do some live coding!

We hope you can join us!

Stuck? Get help on our Discord.