跳转到主要内容

标签(标签)

资源精选(342) Go开发(108) Go语言(103) Go(99) angular(82) LLM(78) 大语言模型(63) 人工智能(53) 前端开发(50) LangChain(43) golang(43) 机器学习(39) Go工程师(38) Go程序员(38) Go开发者(36) React(33) Go基础(29) Python(24) Vue(22) Web开发(20) Web技术(19) 精选资源(19) 深度学习(19) Java(18) ChatGTP(17) Cookie(16) android(16) 前端框架(13) JavaScript(13) Next.js(12) 安卓(11) 聊天机器人(10) typescript(10) 资料精选(10) NLP(10) 第三方Cookie(9) Redwoodjs(9) ChatGPT(9) LLMOps(9) Go语言中级开发(9) 自然语言处理(9) PostgreSQL(9) 区块链(9) mlops(9) 安全(9) 全栈开发(8) OpenAI(8) Linux(8) AI(8) GraphQL(8) iOS(8) 软件架构(7) RAG(7) Go语言高级开发(7) AWS(7) C++(7) 数据科学(7) whisper(6) Prisma(6) 隐私保护(6) JSON(6) DevOps(6) 数据可视化(6) wasm(6) 计算机视觉(6) 算法(6) Rust(6) 微服务(6) 隐私沙盒(5) FedCM(5) 智能体(5) 语音识别(5) Angular开发(5) 快速应用开发(5) 提示工程(5) Agent(5) LLaMA(5) 低代码开发(5) Go测试(5) gorm(5) REST API(5) kafka(5) 推荐系统(5) WebAssembly(5) GameDev(5) CMS(5) CSS(5) machine-learning(5) 机器人(5) 游戏开发(5) Blockchain(5) Web安全(5) Kotlin(5) 低代码平台(5) 机器学习资源(5) Go资源(5) Nodejs(5) PHP(5) Swift(5) devin(4) Blitz(4) javascript框架(4) Redwood(4) GDPR(4) 生成式人工智能(4) Angular16(4) Alpaca(4) 编程语言(4) SAML(4) JWT(4) JSON处理(4) Go并发(4) 移动开发(4) 移动应用(4) security(4) 隐私(4) spring-boot(4) 物联网(4) nextjs(4) 网络安全(4) API(4) Ruby(4) 信息安全(4) flutter(4) RAG架构(3) 专家智能体(3) Chrome(3) CHIPS(3) 3PC(3) SSE(3) 人工智能软件工程师(3) LLM Agent(3) Remix(3) Ubuntu(3) GPT4All(3) 软件开发(3) 问答系统(3) 开发工具(3) 最佳实践(3) RxJS(3) SSR(3) Node.js(3) Dolly(3) 移动应用开发(3) 低代码(3) IAM(3) Web框架(3) CORS(3) 基准测试(3) Go语言数据库开发(3) Oauth2(3) 并发(3) 主题(3) Theme(3) earth(3) nginx(3) 软件工程(3) azure(3) keycloak(3) 生产力工具(3) gpt3(3) 工作流(3) C(3) jupyter(3) 认证(3) prometheus(3) GAN(3) Spring(3) 逆向工程(3) 应用安全(3) Docker(3) Django(3) R(3) .NET(3) 大数据(3) Hacking(3) 渗透测试(3) C++资源(3) Mac(3) 微信小程序(3) Python资源(3) JHipster(3) 语言模型(2) 可穿戴设备(2) JDK(2) SQL(2) Apache(2) Hashicorp Vault(2) Spring Cloud Vault(2) Go语言Web开发(2) Go测试工程师(2) WebSocket(2) 容器化(2) AES(2) 加密(2) 输入验证(2) ORM(2) Fiber(2) Postgres(2) Gorilla Mux(2) Go数据库开发(2) 模块(2) 泛型(2) 指针(2) HTTP(2) PostgreSQL开发(2) Vault(2) K8s(2) Spring boot(2) R语言(2) 深度学习资源(2) 半监督学习(2) semi-supervised-learning(2) architecture(2) 普罗米修斯(2) 嵌入模型(2) productivity(2) 编码(2) Qt(2) 前端(2) Rust语言(2) NeRF(2) 神经辐射场(2) 元宇宙(2) CPP(2) 数据分析(2) spark(2) 流处理(2) Ionic(2) 人体姿势估计(2) human-pose-estimation(2) 视频处理(2) deep-learning(2) kotlin语言(2) kotlin开发(2) burp(2) Chatbot(2) npm(2) quantum(2) OCR(2) 游戏(2) game(2) 内容管理系统(2) MySQL(2) python-books(2) pentest(2) opengl(2) IDE(2) 漏洞赏金(2) Web(2) 知识图谱(2) PyTorch(2) 数据库(2) reverse-engineering(2) 数据工程(2) swift开发(2) rest(2) robotics(2) ios-animation(2) 知识蒸馏(2) 安卓开发(2) nestjs(2) solidity(2) 爬虫(2) 面试(2) 容器(2) C++精选(2) 人工智能资源(2) Machine Learning(2) 备忘单(2) 编程书籍(2) angular资源(2) 速查表(2) cheatsheets(2) SecOps(2) mlops资源(2) R资源(2) DDD(2) 架构设计模式(2) 量化(2) Hacking资源(2) 强化学习(2) flask(2) 设计(2) 性能(2) Sysadmin(2) 系统管理员(2) Java资源(2) 机器学习精选(2) android资源(2) android-UI(2) Mac资源(2) iOS资源(2) Vue资源(2) flutter资源(2) JavaScript精选(2) JavaScript资源(2) Rust开发(2) deeplearning(2) RAD(2)

TLDR;

By using Angular Scully and Prisma we have a powerful ecosystem where we can leverage full type safety and easily connect to a database that contains data that will be injected into the components by Scully. After the Scully process, we can upload our app to a CDN and have a fully working SEO-friendly Angular app.

What is Prisma?

Prisma is an open-source ORM, it consists of three parts:

  • Prisma Client: Auto-generated and type-safe query builder for Node.js & TypeScript
  • Prisma Migrate: Migration system
  • Prisma Studio: GUI to view and edit data in your database

Prisma Client can be used in any Node.js (supported versions) environment. The power of Prisma is that they have a good and powerful type safety solution when using it with Typescript, and by default supports a set of Easy to use querIes.

What is Scully

Scully is the static site generator for Angular projects looking to embrace the Jamstack.

It will use your application and will create a static index.html for each of your pages/routes. Every index.html will have the content already there, and this will make your application show instantly for the user. Also, this will make your application very SEO-friendly. On top of this, your SPA will still function as it did before.

How to set up an Angular app with Scully?

In this article, we are not going very deep into the setup of Angular and Scully. For a good reference, you can have a look at the repo. Below are the steps you can follow along:

First, let’s set up a new Angular app

npx ng new ng-scully --minimal

Second, let’s add Scully to the Angular application

ng add @scullyio/init

Scully schematics will do the following:

  • Add Scully dependencies to package.json and install it
  • Import ScullyLibModule to AppModule
  • Add 'zone.js/dist/task-tracking' to polyfills.ts
  • Add scully.<project_name>.config.ts to the root directory. This is Scully configuration file that we will utilize to configure Scully.

Now we have a setup that works with Angular, but we need to take one step more for this demo.

ng generate @scullyio/init:blog

The above command adds the blog modules' routes to the Angular application.
In addition, it creates a ./blog folder for the blog's markdown files.

How to use Prisma with Scully?

I’ve made the choice to use postgress as my database, in combination with docker.

Below I’m showing you my docker-compose file:

version: '3'
services:
 postgres:
    image: postgres
    ports:
      - "5432:5432"
    restart: always
    environment:
      POSTGRES_USER: prisma
      POSTGRES_PASSWORD: prisma
    volumes:
      - postgres:/var/lib/postgresql/data
volumes:
  postgres:

Now we only need to run it so that Prisma can connect to it.

docker-compose up -d

Now we can continue with Prisma, first we need to install Prisma

npm install prisma --save-dev

After installation we will run the init command as shown below:

npx prisma init

This init command will setup Prisma with the required files in the directory.

After this we need to change the .env file with our database connection:

DATABASE_URL="postgresql://prisma:prisma@localhost:5432/mydb?schema=public"

Setup Prisma configuration

To use Prisma with Scully we first need to add the setup for Prisma.

As Prisma is an ORM for a database we need to tell Prisma what tables and/ or database it is connected to. This information is placed in the schema.prisma file:

// This is your Prisma schema file,

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}

model User {
  id        Int      @id @default(autoincrement())
  name      String?
  email     String?  @unique
  createdAt DateTime @default(now()) @map(name: "created_at")
  updatedAt DateTime @updatedAt @map(name: "updated_at")
  posts     Post[]

  @@map(name: "users")
}

Note: You're occasionally using @mapand@@mapto to transform some field and model names to different column and table names in the underlying database.

This Prisma schema defines two models, each of which will map to a table in the underlying database: User and Post. Notice that there's also a relation (one-to-many) between the two models, via the author field on Post and the posts field on User.

Now that we have our schema defined, we need to create our tables in our database. This can be done by running the following CLI command:

npx prisma db push

You should see the following output:

Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
Datasource "db": PostgreSQL database "mydb", schema "public" at "localhost:5432"
The database is already in sync with the Prisma schema.
✔ Generated Prisma Client (3.8.1 | library) to .\node_modules\@prisma\client in
75ms

As our database is ready to be used, let’s add some data. We are going to use Prisma Studio, this is an easy way to explore and manipulate the data. You can open up Prisma Studio by running

npx prisma studio

Create a Prisma Scully Plugin

As we now have an operating database and an ORM library (Prisma) we now can use all these parts to receive the data and use it in Scully. Let’s start by creating the first basis for our custom plugin.

import { PrismaClient } from "@prisma/client";
import {
  HandledRoute,
  logError,
  registerPlugin,
  RouteConfig,
} from "@scullyio/scully";
import { convertAndInjectContent } from "@scullyio/scully/src/lib/renderPlugins/content-render-utils/convertAndInjectContent";
export const prismaPlugin = "prismaPlugin";
const prisma = new PrismaClient();
const routerPlugin = async (route: string, config: RouteConfig) => {
  // here we are looking up all posts
  const data = await prisma.post.findMany({
    // where the published property is true
    where: { published: true },
    // and we include the author
    include: {
      author: {
        // and we only want the author's name
        select: { name: true },
      },
    },
  });
  return Promise.resolve(
    // let's loop over all posts
    data.map((post) => {
      // and return a new route for each post
      const { id, title, published, author, content } = post;
      return {
        ...config,
        route: `/blog/${id}`,
        data: {
          id,
          title,
          published,
          author: author.name,
          content,
        },
      } as HandledRoute;
    })
  );
};
registerPlugin("router", prismaPlugin, routerPlugin);

async function prismaDomPlugin(dom: any, route: HandledRoute | undefined) {
  if (!route) return dom;
  try {
    try {
      // here we use the power of scully and use the filehandler to convert the content to html
      return convertAndInjectContent(dom, route.data.content, "md", route);
    } catch (e) {
      logError(`Error during contentText rendering`);
      console.error(e);
    }
    return dom;
  } catch (e) {}
}

registerPlugin("postProcessByDom", prismaPlugin, prismaDomPlugin);

Let’s break this code down from the top.

import { PrismaClient } from '@prisma/client';
import { logError, registerPlugin, RouteConfig } from '@scullyio/scully';

//define our plugin name
export const prismaPlugin = 'prismaPlugin';

// setup our PrismaClient
const prisma = new PrismaClient();

// our router plugin
const routerPlugin = async (route: string, config: RouteConfig) => {
...
};

Now we are going to retrieve the posts with the Prisma client. When all the data is gathered we will return new routes that will be used on our post-render step.

const prisma = new PrismaClient();
const routerPlugin = async (route: string, config: RouteConfig) => {
  // here we are looking up all posts
  const data = await prisma.post.findMany({
    // where the published property is true
    where: { published: true },
    // and we include the author
    include: {
      author: {
        // and we only want the author's name
        select: { name: true },
      },
    },
  });
  return Promise.resolve(
    // let's loop over all posts
    data.map((post) => {
      // and return a new route for each post
      const { id, title, published, author, content } = post;
      return {
        ...config,
        route: `/blog/${id}`,
        data: {
          id,
          title,
          published,
          author: author.name,
          content,
        },
      } as HandledRoute;
    })
  );
};

The post-process plugin is used to transform the render HTML. In our custom plugin, we make use of the Scully system, the converAndInjectContent function will look at the fileHandler plugins, and if it finds an extension of a file type. In our case, it will look for the fileHandler for markdown files. This plugin will transform our data coming from the database from markdown to HTML.

async function prismaDomPlugin(dom: any, route: HandledRoute | undefined) {
  if (!route) return dom;
  try {
    try {
      // here we use the power of scully and use the filehandler to convert the content to html
      return convertAndInjectContent(dom, route.data.content, "md", route);
    } catch (e) {
      logError(`Error during contentText rendering`);
      console.error(e);
    }
    return dom;
  } catch (e) {}
}

Now that we have set up our plugin, we need to make one new change to our Scully configuration. We need to change the original blog route to use our custom plugin, first, we need to import our custom plugin

import { prismaPlugin } from "./scully/plugins/plugin";

Then we need to define our router and post process plugin to being used in our blog route.

routes: {
    "/blog/:slug": {
      type: prismaPlugin,
    }
  }

Finally, we are ready to run our Scully system to scan for new routes, run npx scully --scan

$ npx scully --scan
  ✔ new Angular build files imported
  ✔ Starting servers for project "asp-example"
  ✔ Started Angular distribution server on "http://localhost:1864/" 
  ✔ Started Scully static server on "http://localhost:1668/"
  ✔ Scully Development Server is up and running
  ✔ Puppeteer is being launched
  ✔ Successfully scanned Angular app for routes
  ✔ Successfully added routes created from routePlugins
  ✔ Route list created in files:
     ".\src\assets\scully-routes.json",
     "dist\static\assets\scully-routes.json",
     "dist\asp-example\assets\scully-routes.json"

  ✔ Route "/blog" rendered into ".\dist\static\blog\index.html" 
  ✔ Route "/home" rendered into ".\dist\static\home\index.html" 
  ✔ Route "/" rendered into ".\dist\static\index.html" 
  ✔ Route "/blog/1" rendered into ".\dist\static\blog\1\index.html" 

Total time used 5.74 seconds
  4 pages have been created
  Rendering the pages took 2.99 seconds
  That is 1.34 pages per second,
  or 749 milliseconds for each page.

  Finding routes in the angular app took 2.68 seconds
  Pulling in route-data took 47 milliseconds

We now have our first page rendered with Angular, Scully, and Prisma.

Conclusion

With Prisma we have a powerful type of safety solution to connect to a database, combine this with the power of Scully we cn easily create static pages from an Angular application and upload it to a CDN.B

标签