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

推荐订阅源

大猫的无限游戏
大猫的无限游戏
Webroot Blog
Webroot Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Threat Research - Cisco Blogs
V2EX - 技术
V2EX - 技术
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
S
Schneier on Security
I
InfoQ
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The GitHub Blog
The GitHub Blog
S
Security @ Cisco Blogs
O
OpenAI News
W
WeLiveSecurity
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
人人都是产品经理
人人都是产品经理
Cloudbric
Cloudbric
The Last Watchdog
The Last Watchdog
The Hacker News
The Hacker News
Google Online Security Blog
Google Online Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
NISL@THU
NISL@THU
T
Tailwind CSS Blog
V
Visual Studio Blog
PCI Perspectives
PCI Perspectives
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
D
DataBreaches.Net
B
Blog RSS Feed
N
News and Events Feed by Topic
N
News and Events Feed by Topic
H
Heimdal Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
腾讯CDC
Latest news
Latest news
V
Vulnerabilities – Threatpost
Hacker News: Ask HN
Hacker News: Ask HN
WordPress大学
WordPress大学
V
V2EX
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Register - Security
The Register - Security
Help Net Security
Help Net Security

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 Zero-config Debugging with Deno and OpenTelemetry | Deno Exploring Art with TypeScript, Jupyter, Polars, and Observable Plot | Deno Deno v Oracle Update 3: Fighting the JavaScript Trademark | Deno Build a custom RAG AI agent in TypeScript and Jupyter | Deno How to get deep traces in your Node.js backend with OTel and Deno | Deno toranoana.deno #20 登録受付中(2025年3月14日) | Deno Node just added TypeScript support. What does that mean for Deno? | Deno The Dino 🦕, the Llama 🦙, and the Whale 🐋 | Deno Publish a lint rule, get a prize | Deno Deno 2.2: OpenTelemetry, Lint Plugins, node:sqlite | Deno If you're not using npm specifiers, you're doing it wrong | Deno How Deno's documentation is evolving | Deno Oracle justified its JavaScript trademark with Node.js—now it wants that ignored | Deno Introducing the JSR open governance board | Deno Intro to Wasm in Deno | Deno Announcing OpenAI on JSR | Deno Deno in 2024 | Deno Goodbye WinterCG, welcome WinterTC | Deno Build a SolidJS app with Deno | Deno Run your Next.js SSR app on Deno Deploy | Deno Solve Advent of Code 2024 with Deno and Win Prizes! | Deno Deno v. Oracle: Canceling the JavaScript Trademark | Deno Deno 2.1: Wasm Imports and other enhancements | Deno Build a Typesafe API with tRPC and Deno | Deno Self-contained Executable Programs with Deno Compile | Deno Build a Database App with Drizzle ORM and Deno | Deno Introducing your new JavaScript package manager: Deno | Deno Announcing Growthbook on JSR | Deno Build an Astro site with Deno | Deno How to convert CommonJS to ESM | Deno Announcing Deno 2 | Deno The Final Touches: What’s New In v2.0.0-rc.10 | Deno Announcing Stable V8 Bindings for Rust | Deno Deno 2.0 Release Candidate | Deno Secure, efficient private npm registries with Cloudsmith and Deno | Deno Painting the Plane as We Fly It: Designing JSR | Deno Introducing Web Cache API support on Deno Deploy | Deno Deno 1.46: The Last 1.x Release | Deno Protect your cloud spend with new Deno Deploy spend limits | Deno What we got wrong about HTTP imports | Deno Benchmarking AWS Lambda Cold Starts Across JavaScript Runtimes | Deno Announcing Supabase on JSR | Deno Deno 1.45: Workspace and Monorepo Support | Deno Introducing KV Backup for Deno Subhosting | Deno A Gentle Intro to TypeScript | Deno Announcing Hono on JSR | Deno How We Made the Deno Language Server Ten Times Faster | Deno How the Guardian uses Deno to audit accessibility and performance across their 2.7 million articles | Deno Introducing More Flexible Domain Association for Deno Subhosting | Deno The stabilization process of the Standard Library has begun | Deno Deno 1.44: Private npm registries, improved Node.js compat, and performance boosts | Deno How we built a secure, performant, multi-tenant cloud platform to run untrusted code | Deno The Deno Standard Library is now available on JSR | Deno How to document your JavaScript package | Deno Your Low Code Solution Needs an Escape Hatch | Deno Deno 1.43: Improved Language Server performance | Deno How Slack used Deno to save months of engineering effort in launching their new platform | Deno JSR Is Not Another Package Manager | Deno Announcing the Hookdeck SDK on JSR | Deno Announcing the Neon Serverless Driver on JSR | Deno An intro to TSConfig for JavaScript Developers | Deno How we built JSR | Deno How Netlify used Deno Subhosting to build a successful edge functions product | Deno Introducing Simpler Project Creation in Deno Deploy | Deno Deno 1.42: Better dependency management with JSR | Deno Introducing deployctl, the command line interface for Deno Deploy | Deno Introducing JSR - the JavaScript Registry | Deno How to add Monaco to a Next.js app and securely run untrusted user code | Deno Survey Results and Roadmap | Deno Deno 1.41: smaller deno compile binaries | Deno
How to build a static site with Lume | Deno
Óscar Otero · 2022-12-07 · via Deno

This is a guest blog written by Óscar Otero, creator of Lume.

Deno is a great choice to create dynamic web applications and APIs, especially when used with Deno Deploy to generate responses at the edge.

But for use cases that don’t require dynamic responses from the server, like blogs, documentation, and landing pages, a static site (a pre-built site with the exact HTML, CSS and JavaScript files to be delivered to the browser) is a better and more performant alternative.

In this tutorial we’ll learn how to create a static site using Lume (pronounced /lume/), a fast and extremely flexible, composable, and extensible static site generator written in Deno.

View source or live demo.

Setup

The recommended way to setup a Lume project is by running the command:

deno run -Ar --unstable https://deno.land/x/lume/init.ts

After a couple of questions, you will see 3 new files in your working directory:

  • _config.ts: The configuration file to customise Lume.
  • deno.json: The Deno configuration file with some useful tasks to run Lume.
  • import_map.json: The import map file used by Deno to resolve bare specifiers.

Additionally, it’s highly recommended to use the Deno extension if you’re on VSCode. (Learn about configuring Deno with VSCode.)

Building a blog: the easy way

Blogs are the most common usage example for a static site generator and Lume, of course, can build one for you. If you are not looking for something too complicated, probably the “Simple blog” theme is enough. You only need to import it in the _config.ts file and use it.

import lume from "lume";
import blog from "https://deno.land/x/lume_theme_simple_blog@v0.2.1/mod.ts";

const site = lume().use(blog());

export default site;

Then save your posts using the markdown + front matter format in the /posts/ folder. For example:

---
title: Static sites with Lume + Deno Deploy
date: 2022-11-05
author: Óscar Otero
tags:
  - Deno
  - Static site generators
---

Deno is always a great choice to create dynamic web applications and APIs,
especially when it's combined with Deno Deploy to generate responses at the
edge. ...

Run deno task serve and you will see your new blog at localhost:3000!

But I want to craft something by myself

Okay, understood! Instead of using an existing theme, let’s build something from scratch.

Getting started

Lume doesn’t require any file structure to work, but for this demo, we will save all posts files in a directory named /posts. So we have the following structure:

|_ posts/
|  |_ my-first-post.md
|  |_ my-second-post.md
|_ config.ts
|_ deno.json
|_ import_map.json

Run deno task serve to see the site at localhost:3000. You will see a 404 error page because the index file doesn’t exist yet.

Getting a 404 page not found

But you can see the post. By default, the urls of the posts are calculated based on the source path. For example the file /posts/my-first-post.md outputs the URL http://localhost:3000/posts/my-first-post/.

My first post

The layout

As you can see, the page only shows the markdown content rendered as HTML. Let’s create a layout to wrap this content into a proper HTML structure. By default, the layouts are stored in the special folder _includes, so we need to create this folder and the file post.njk inside with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
</head>
<body>
  <main>
    <article>
      <header>
        <h1>{{ title }}</h1>
        <p>By {{ author }}</p>
      </header>

      {{ content | safe }}
    </article>
  </main>
</body>
</html>

The .njk extension is for Nunjucks a popular templating language created by Mozilla and supported by Lume by default. Of course, you can use other formats like JavaScript, TypeScript or even JSX, Pug, Eta, etc (using plugins), but let’s keep it simple for now.

We’ll create a _data.yml file inside the posts folder with the following content:

layout: post.njk
type: post

This file assigns these two variables to all posts in this directory.

Let’s ignore the type variable for now.

The layout variable is a special value containing the filename of the layout used to render the page. This means that all pages in this directory will use the _includes/post.njk file as the layout. Note that the layout can access to the values of the front matter of the posts, like title or author.

Our post looks a bit better now!

First post but with some style

List all posts

Let’s say we want to show a list of all posts in the homepage. For this example I’m going to create the homepage in TypeScript, so we need to create the index.tmpl.ts file in the root with the following code:

import type { PageData } from "lume/core.ts";

export default function ({ search }: PageData) {
  const posts = search.pages("type=post");

  return `
    <h2>Posts</h2>
    <ul>
      ${
    posts.map((post) =>
      `<li><a href="${post.data.url}">${post.data.title}</a></li>`
    ).join("")
  }
    </ul>
  `;
}

Building pages with TypeScript in Lume is easy, we only need to export default a function that returns the page content as string.

This function receives the page context data as the first parameter, including some interesting helpers like search that we can use to query and return all pages with the type=post variable. (Remember the type value that we inserted in the posts/_data.yml file before? It was only a flag to easily select these pages here.)

Our homepage looks something like this:

The index page

I could include the full HTML code in the page but I love layouts, so I’ve created the following _includes/homepage.njk layout file:

---
title: The Óscar's blog
---

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
</head>
<body>
  <main>
    <header>
      <h1>{{ title }}</h1>
    </header>

    {{ content | safe }}
  </main>
</body>
</html>

Now we have to configure the index.tmpl.ts file to use this layout. TypeScript files don’t have front matter to store data, they just expose the values as named exports:

import type { PageData } from "lume/core.ts";

export const layout = "homepage.njk";

export default function ({ search }: PageData) {
  const posts = search.pages("type=post");

  return `
    <h2>Posts</h2>
    <ul>
      ${
    posts.map((post) =>
      `<li><a href="${post.data.url}">${post.data.title}</a></li>`
    ).join("")
  }
    </ul>
  `;
}

The homepage looks a bit better now:

Styling the home page

Adding styles

Lume has a bunch of plugins to work with JavaScript, to support formats like JSX, MDX, etc. For styling purposes, there are some available plugins to work with SASS, PostCSS, WindiCSS or LighningCSS.

For simplicity, for this demo we’re going to use the awesome missing.css (by the way, the documentation site is also built with Lume). This css file provides some nice styles out of the box, without need to modify our HTML. To do that, just include the <link rel="stylesheet" href="https://the.missing.style/"> line in the two layouts we just created.

The home page but much better styled

Ready to deploy

One of the many advantages of the static sites is the hosting. You can host your site anywhere, with almost no server requirements.

In this demo we are going to use Deno Deploy to serve the site. Thanks to its design, where all incoming requests are handled by a JavaScript file, we can customise how the files of your site will be delivered.

Step 1: Create a project in Deno Deploy

Go to Deno Deploy and create a new project. You will see a screen like this:

Create a new project in Deno Deploy

An important thing when selecting the branch, is to use the GitHub Action mode. This is because Deno Deploy doesn’t have a CI to build the site, so we need to use the GitHub Actions workflows to build and upload the static site to Deno Deploy.

Then click in the Link button and you will see the following screen:

Get the GitHub Action for Deno Deploy

Deno Deploy has generated the code needed to configure the GitHub Actions workflow. Copy this code and save it into .github/workflows/deploy.yml.

Step 2: Configure GitHub Actions

The GitHub Action workflow file that we have just created needs a couple of tweaks marked as #TODO comments:

  • Set up the build step. In our case we need to setup Deno and run deno task build.
  • Update the entrypoint to use deno_std’s file_server.ts, with the root set to ./_site.

Note that if you want to use Lume’s middleware, such as expires for caching or not_found to show a custom 404 page, you would need to create a new serve.ts, add your middleware, and set that as the entrypoint for Deno Deploy.

After these modifications, this is the final version:

name: Deploy
on: [push]

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    permissions:
      id-token: write 
      contents: read 

    steps:
      - name: Clone repository
        uses: actions/checkout@v3

      - name: Setup Deno environment
        uses: denoland/setup-deno@v1
        with:
          deno-version: v1.x

      - name: Build site
        run: deno task build

      - name: Upload to Deno Deploy
        uses: denoland/deployctl@v1
        with:
          project: oscarotero-lume-blog-demo
          entrypoint: https://deno.land/std@0.167.0/http/file_server.ts
          root: ./_site

Push the changes to GitHub and your site will be built and uploaded to Deno Deploy in a few seconds.

Successful deployment on Deno Deploy

Click in the View blue button to see your new blog at *.deno.dev (or a different domain if you add a custom domain).

Oscars blog served from Deno Deploy

And that’s all. It was easy, wasn’t it? Take a look at the Lume documentation site to learn more about this static site generator and see real examples in the Showcase section.

Stuck? Come say hi in Deno’s Discord!