如何構建自己的免費無服務器評論框

by Shaun Persad

通過Shaun Persad

如何構建自己的免費無服務器評論框 (How you can build your own free, serverless comment box)

Contentful’s flexible content modeling goes far beyond blog posts. Here’s how you can leverage Contentful and Netlify to create a nested commenting system that’s easy to moderate and deploy.

Contentful靈活的內容建模遠遠超出了博客文章。 這是如何利用Contentful和Netlify創建易于審核和部署的嵌套評論系統。

動機 (The motivation)

I find most commenting systems out there to be…lacking. Disqus can often be slow to render, and their user tracking behavior doesn’t have the best reputation. Meanwhile, Facebook’s comments plugin is quite nice, but of course is limited to Facebook users.

我發現那里的大多數評論系統都……不足。 Disqus的呈現速度通常很慢,并且它們的用戶跟蹤行為也不是最好的聲譽。 同時,Facebook的評論插件相當不錯,但當然僅限Facebook用戶。

What I really wanted was the native speed and approach to nested commenting and moderation taken by sites like Hacker News and Indie Hackers, but I needed a solution that would be portable to multiple projects.

我真正想要的是像Hacker News和Indie Hackers這樣的網站采用固有的速度和方法來進行嵌套評論和主持人,但是我需要一個可移植到多個項目的解決方案。

There just didn’t seem to be a great fit out there, so I decided to build my own, with my wish list of features:

似乎沒有什么合適的選擇,所以我決定建立我自己的功能清單,并提供以下功能:

  • Free

    自由

  • Low barrier to entry — minimal steps required to submit a comment

    進入門檻低 -提交評論所需的最少步驟

  • Low maintenance — serverless, to not worry about hosting or scaling

    低維護 —無服務器,不用擔心托管或擴展

  • Easy moderation — use a dashboard to perform CRUD on comments

    輕松審核 -使用儀表板對評論執行CRUD

  • Peformant — super-fast to appear on the page

    Peformant-超快速出現在頁面上

  • Flexible — users should be able to log in via multiple platforms

    靈活 -用戶應該能夠通過多個平臺登錄

  • Powerful — comments should have smart formatting features

    強大 -注釋應具有智能格式設置功能

  • High comment quality — users can upvote and downvote comments

    高評論質量 -用戶可以對評論進行投票和降級

  • Subscriptions — users can receive notifications when their comments are replied to

    訂閱 -回復他們的評論時,用戶可以收到通知

Over the course of this series, we will build out a commenting system that incorporates each of the above aspects.

在本系列的整個過程中,我們將構建一個包含上述各個方面的評論系統。

計劃 (The plan)

Our stack will initially include:

我們的堆棧最初將包括:

  • Contentful as a database and moderation dashboard

    內容豐富,可作為數據庫和審核儀表板

  • AWS Lambda via Netlify as our back-end

    通過Netlify的 AWS Lambda作為我們的后端

  • React on the front-end

    在前端做出React

We will create a React component to serve as our comment box, and supply it with the ability to make an API call to Contentful to fetch comments as necessary. It will also be able to make an API call to our Lambda function to post a comment to Contentful.

我們將創建一個React組件作為我們的注釋框,并為它提供對Contentful進行API調用以根據需要獲取注釋的功能。 它還將能夠對我們的Lambda函數進行API調用,以對Contentful發表評論。

Project-wise, our Lambda function will live along-side our front-end code. Both the front-end and back-end will be set up to be continuously deployed via Netlify.

在項目方面,我們的Lambda函數將與我們的前端代碼一起使用。 前端和后端都將設置為通過Netlify進行連續部署。

By the way, the above stack is all free! Well, mostly. Unless you’re going to be doing over 10,000 comments, it’s free. Also, I’m not affiliated with any of these companies…I just love their stuff :)

順便說一下,以上堆棧都是免費的! 好吧,主要是。 除非您要進行超過10,000條評論,否則它是免費的。 另外,我與這些公司都不隸屬...我只是喜歡他們的東西:)

在10秒內滿意 (Contentful in 10 seconds)

If you’re not already familiar with Contentful and how it works, it’s a “headless” (API-driven) CMS. You’re able to model your content with different fields and field types, and then you create content based on those models. You can build your front-end however you like, and query for your data using their API. It’s super flexible, and their dashboard is quite nice to use. It’s basically the best thing to happen to CMS’s since, well, ever?

如果您還不熟悉Contentful及其工作原理 ,那么它就是“無頭”(由API驅動)的CMS。 您可以使用不同的字段和字段類型對內容建模,然后根據這些模型創建內容。 您可以根據需要構建自己的前端,并使用其API查詢數據。 它非常靈活,他們的儀表板非常好用。 從根本上說,這是CMS發生的最好的事情了?

I was already using Contentful for my blog posts, so I wondered, could it be viable to host comments as well? I’m happy to report that the answer is yes! However, a few of the items on my wishlist don’t quite work out using just Contentful. But don’t worry, we’ll get there…in the subsequent posts of this series.

我已經在博客文章中使用了Contentful,所以我想知道是否也可以托管評論? 我很高興地報告答案是肯定的! 但是,我的愿望清單上的某些項目使用Contentful不太可行。 但是請放心,我們將會到達……在本系列的后續文章中。

We’ll be using Contentful because:

我們將使用Contentful是因為:

  • flexible data modeling

    靈活的數據建模
  • convenient API

    方便的API
  • moderation via a dashboard

    通過儀表板進行審核
  • you may already be using it for your website/blog that needs comments

    您可能已經將其用于需要評論的網站/博客

在10秒內完成Netlify (Netlify in 10 seconds)

I think Netlify has by far the most enjoyable deployment experience for front-end apps. It links to your GitHub repo and sets you up to continuously deploy a static site to CDN-backed hosting. They also have Netlify Functions, which let you deploy to AWS Lambda without any of the pain of messing around in AWS.

我認為Netlify迄今為止具有最令人滿意的前端應用程序部署體驗。 它鏈接到您的GitHub存儲庫,并設置為將靜態站點連續部署到CDN支持的托管。 它們還具有Netlify Functions ,可讓您部署到AWS Lambda,而不會在AWS上亂成一團 。

You can get started at their docs, but honestly, their dashboard is so easy to use and understand, I recommend just logging in and poking around.

您可以從他們的文檔開始,但老實說,他們的儀表板非常易于使用和理解,我建議您先登錄并四處瀏覽。

We’ll be using Netlify because:

我們將使用Netlify是因為:

  • painless AWS Lambda integration

    無痛的AWS Lambda集成
  • you may already be using it for your website/blog that needs comments

    您可能已經將其用于需要評論的網站/博客
  • If you’re not already using it, you can still deploy the Lambda functions we create to AWS itself

    如果尚未使用它,您仍然可以將我們創建的Lambda函數部署到AWS本身

等等,沒有“ 10秒鐘后React”嗎? (Wait, no “React in 10 seconds”?)

I don’t know if 10 seconds is enough to do React justice. If you haven’t yet learned it, you should! But skip the Redux and Flux stuff. Chances are you don’t need any of that (but that’s another topic for another time).

我不知道10秒鐘是否足以完成React正義。 如果您還沒有學過,那應該! 但是跳過Redux和Flux的內容。 您可能不需要其中任何一個(但這是另一回事了)。

Contentful中的內容建模 (Content modeling in Contentful)

Now down to business.

現在正事。

There are two different approaches we could take regarding how we handle our users: authless and logged-in commenting:

關于我們如何處理用戶,我們可以采取兩種不同的方法: authless登錄評論:

  • Authless — anyone can leave a comment simply by supplying their name

    無需身份驗證-任何人都可以通過提供姓名來發表評論
  • Logged-in — only users who are authenticated in some auth system can comment

    登錄-只有在某些身份驗證系統中經過身份驗證的用戶才能評論

I prefer logged-in commenting, because in my opinion, the conversations tend to be more civilized. Plus, you tend to avoid spam altogether. On the flipside, the barrier to create a comment is slightly higher.

我更喜歡登錄評論,因為我認為對話通常更加文明。 另外,您傾向于完全避免垃圾郵件。 另一方面,創建評論的障礙稍高。

However, we will start off with authless commenting, because it’s simpler to implement. Once we get our feet wet, we’ll jump into logged-in commenting in Part 2.

但是,我們將從無認證注釋開始,因為它更易于實現。 一旦弄濕了,我們將在第2部分中進入登錄評論。

Regardless, we’re going to first need to create a content model to represent our comments.

無論如何,我們首先需要創建一個內容模型來表示我們的評論。

For both authless and logged-in approaches, our Comment content model will remain mostly the same as well, though there will be some later changes to the Author field, as noted below.

對于無認證方法和登錄方法,我們的評論內容模型也將基本保持不變,盡管稍后會在“ 作者”字段中進行一些更改,如下所述。

評論內容模型 (The Comment content model)

This is the model at the heart of our commenting system. Comments should have four fields:

這是我們評論系統的核心模型。 注釋應包含四個字段:

Body

身體

  • The actual body of the comment

    評論的實際內容
  • Mark this one as the entry title

    將此標記為條目標題
  • Feel free to also set a maximum and/or minimum value on its length

    還可以設置其長度的最大值和/或最小值

Author

作者

  • A unique identifier representing the user who posted this comment.

    代表發布此評論的用戶的唯一標識符。
  • For authless commenting, you’d use short text and fill in the author’s name in this field

    對于無認證評論,您將使用短文本并在此字段中填寫作者的姓名
  • For logged-in commenting, this field will become a reference to the upcoming CommentAuthor model

    對于已登錄的評論,此字段將成為對即將到來的CommentAuthor模型的引用

Subject

學科

  • The unique ID of the blog post (or equivalent) that these comments belong to

    這些評論所屬的博客文章的唯一ID(或等效名稱)
  • It can also be the URL of the page

    也可以是頁面的URL
  • For maximum flexibility, I chose not to assume that you’re storing your blog posts in Contentful, or else this would be a reference field instead of short text

    為了獲得最大的靈活性,我選擇不假定您將博客文章存儲在Contentful中,否則這將是一個參考字段,而不是短文本

ParentComment

家長評論

  • If this comment is a reply to another comment, we’ll reference that comment here

    如果此評論是對其他評論的回復,我們將在此處引用該評論
  • This field is what enables us to create nested comments

    該字段使我們能夠創建嵌套注釋

實施無認證評論 (Implementing authless commenting)

For this implementation, we want the user to enter their name before they are able to post a comment. I recommend doing an initial read-through of the following steps, and then check out the final demo project at the end to see how it all comes together.

對于此實現,我們希望用戶在發表評論之前輸入他們的姓名。 我建議對以下步驟進行初步閱讀,然后在最后查看最終的演示項目,以了解所有內容如何組合在一起。

前端 (Front-end)

Now that our Comment model is done, it’s time to create our comment box. The good news is that I’ve already made a generic “comment box” React component. It’s designed as a low-order component, where you wrap a higher-order component around it to handle fetching and creating Contentful comments, and other application-specific business logic.

現在,我們的評論模型已經完成,是時候創建我們的評論框了。 好消息是我已經制作了一個通用的“注釋框” React組件。 它被設計為一個低階組件,你環繞它高階組件來處理獲取和創造Contentful意見,以及其他應用程序特定的業務邏輯。

You can install it and the other required packages via npm:

您可以通過npm安裝它和其他必需的軟件包:

npm install react-commentbox contentful contentful-management --save

The GitHub repo has a list of every prop you can pass to it, but minimally, we’ll be implementing and passing these:

GitHub存儲庫列出了您可以傳遞給它的每個道具,但是最少,我們將實現并傳遞這些道具:

  • getComments: a function that returns a promise that resolves to an array of comments, ordered from oldest to newest

    getComments :一個函數,該函數返回一個promise,該promise解析為從最舊到最新的注釋數組

  • normalizeComment: a function that maps your array of comments to objects that the component understands

    normalizeComment :將注釋數組映射到組件可以理解的對象的函數

  • comment: a function that makes an API call to create a comment, and returns a promise

    comment :進行API調用以創建評論并返回promise的函數

  • disabled: set to true when commenting should be disabled

    disabled :應禁用評論時設置為true

  • disabledComponent: the component to show when commenting is disabled

    disabledComponent :禁用評論時顯示的組件

Let’s create our higher-level component:

讓我們創建更高級別的組件:

import React from 'react';import CommentBox from 'react-commentbox';
class MyCommentBox extends React.Component {
state = { authorName: '', authorNameIsSet: false };
onChangeAuthorName = (e) => this.setState({         authorName: e.currentTarget.value     });
onSubmitAuthorName = (e) => {
e.preventDefault();        this.setState({ authorNameIsSet: true });    };}

Notice that the component is in charge of setting the author’s name.

注意,該組件負責設置作者的姓名。

By the way, we’re using the transform-class-properties Babel plugin to avoid tedious constructor setup and function bindings. You don’t need to use it, but it’s quite handy.

順便說一句,我們正在使用transform-class-properties Babel插件來避免繁瑣的構造函數設置和函數綁定。 您不需要使用它,但是非常方便。

Now we need to implement the business-logic props that react-commentbox needs.

現在,我們需要實現react-commentbox所需的業務邏輯道具。

We’ll start off by fetching comments from Contentful, and normalizing them:

我們將從獲取Contentful的注釋并對其進行規范化開始:

// fetch our comments from ContentfulgetComments = () => {
return this.props.contentfulClient.getEntries({        'order': 'sys.createdAt',        'content_type': 'comment',        'fields.subject': this.props.subjectId,    }).then( response => {
return response.items;
}).catch(console.error);};
// turn Contentful entries to objects that react-commentbox expects.normalizeComment = (comment) => {
const { id, createdAt } = comment.sys;    const { body, author, parentComment } = comment.fields;
return {        id,        bodyDisplay: body,        userNameDisplay: author,        timestampDisplay: createdAt.split('T')[0],        belongsToAuthor: false,        parentCommentId: parentComment ? parentComment.sys.id : null    };};

Next, we need to make the API call to create comments:

接下來,我們需要進行API調用以創建注釋:

// make an API call to post a commentcomment = (body, parentCommentId = null) => {
return this.props.postData('/create-comment', {        body,        parentCommentId,        authorName: this.state.authorName,        subjectId: this.props.subjectId    });};

We also need to ask the user for their name before they can comment:

我們還需要先詢問用戶的姓名,然后他們才能發表評論:

// will be shown when the comment box is initially disableddisabledComponent = (props) => {
return (        <form             className="author-name"             onSubmit{ this.onSubmitAuthorName }        >            <input                type="text"                placeholder="Enter your name to post a comment"                value={ this.state.authorName }                onChange={ this.onChangeAuthorName }            />            <button type="submit">Submit</button>        </form>    );};

Then, bring it all together in render, by passing the appropriate props to react-commentbox:

然后,通過將適當的道具傳遞給react-commentbox ,將其全部合并到render

render() {
return (        <div>            <h4>Comments</h4>            <CommentBox                disabled={ !this.state.authorNameIsSet }                getComments={ this.getComments }                normalizeComment={ this.normalizeComment }                comment={ this.comment }                disabledComponent={ this.disabledComponent }            />        </div>    );};

We’ve also set the disabled prop to true while the author's name is not set. This disables the textarea, and shows the disabledComponent form we made to get the author's name.

在未設置作者姓名的情況下,我們還將disabled prop設置為true 。 這將禁用textarea ,并顯示我們為獲得作者姓名而創建的disabledComponent形式。

You can view the complete component here.

您可以在此處查看完整的組件。

You may have noticed that our newly created MyCommentBox also expects a few props itself: subjectId, postData, and contentfulClient.

您可能已經注意到,我們的新創建的MyCommentBox還預計一些道具本身: subjectIdpostDatacontentfulClient

The subjectId is simply some unique ID or URL of the blog post (or equivalent entity) that these comments are for.

subjectId只是這些評論所針對的博客文章(或等效實體)的唯一ID或URL。

postData is a function that makes POST ajax calls. Using fetch, it could look like this:

postData是進行POST ajax調用的函數。 使用fetch ,它看起來可能像這樣:

function postData(url, data) {
return fetch(`.netlify/functions${url}`, {        body: JSON.stringify(data),        headers: {            'content-type': 'application/json'        },        method: 'POST',        mode: 'cors' // if your endpoints are on a different domain    }).then(response => response.json());}

contentfulClient is an instance of the client you get when using the contentful npm package (so make sure you've installed it):

contentfulClient是使用有內容的 npm軟件包時獲得的客戶端的實例(因此請確保已安裝它):

import { createClient } from 'contentful';const contentfulClient = createClient({    space: 'my-space-id',    accessToken: 'my-access-token'});

You can get your space ID in the Contentful dashboard under “Space settings” > “General settings”.

您可以在內容豐富的信息中心的“空間設置”>“常規設置”下獲取空間ID。

You can get your access token from “Space settings” > “API keys” > “Content delivery/preview tokens” > “Add API Key”.

您可以從“空間設置”>“ API密鑰”>“內容交付/預覽令牌”>“添加API密鑰”獲取訪問令牌。

You can then pass in your props when creating MyCommentBox, as shown here.

然后,您可以通過在你的道具制作時MyCommentBox ,如圖所示這里 。

后端 (Back-end)

We will implement our /create-comment endpoint as an AWS Lambda function.

我們將/create-comment端點實現為AWS Lambda函數。

先決條件 (Prerequisites)

To be able to build, preview, and eventually deploy these functions, we’re going to use the handy netlify-lambda npm package. It lets you write your Lambda functions as regular ES6 functions in a particular source directory, and then it builds them in a Lambda-friendly way and puts them in a destination directory, ready for deployment. Even better, it also allows us to preview these functions by deploying them locally.

為了能夠構建,預覽并最終部署這些功能,我們將使用方便的netlify-lambda npm軟件包。 它允許您在特定的源目錄中將Lambda函數編寫為常規的ES6函數,然后以對Lambda友好的方式構建它們,并將它們放置在目標目錄中,以備部署。 更好的是,它還允許我們通過在本地部署這些功能來預覽這些功能。

So, you’ll need to create a particular source directory to store your function (e.g. src/lambda), then create a netlify.toml file in your root directory. Minimally, that file should look like this:

因此,您需要創建一個特定的源目錄來存儲您的函數(例如src/lambda ),然后在根目錄中創建一個netlify.toml文件。 至少,該文件應如下所示:

[build] Functions = "lambda"

The above tells netlify-lambda which directory to put your built functions, meaning it will build the functions in src/lambda and store them in ./lambda. Also, when it comes time to deploy, Netlify will look in the ./lambda directory to deploy to AWS.

上面的內容告訴netlify-lambda將構建的函數放在哪個目錄中,這意味著它將在src/lambda構建函數并將它們存儲在./lambda 。 另外,當需要進行部署時,Netlify將在./lambda目錄中查找以部署到AWS。

To run your Lambda functions locally, use the following command:

要在本地運行Lambda函數,請使用以下命令:

netlify-lambda serve <source directory>

This will allow you to run your functions on http://localhost:9000/{function-name}.

這將允許您在http://localhost:9000/{function-name}上運行函數。

This is the default behavior, but it does not quite match what will happen in production, because it’s running our functions on a different domain from our front-end. In production, our functions will be available on the same domain as our front-end, via the URL {domain}/.netlify/functions/{function-name}.

這是默認行為,但與生產中發生的情況完全不匹配,因為它在我們前端的不同域上運行我們的功能。 在生產中,我們的功能將通過URL {domain}/.netlify/functions/{function-name}在與前端相同的域中提供。

To replicate this behavior locally, we need to proxy front-end calls from /.netlify/functions/{function-name} to http://localhost:9000/{function-name}.

要在本地復制此行為,我們需要將前端調用從/.netlify/functions/{function-name}代理到http://localhost:9000/{function-name}

Accomplishing this differs based on your project setup. I will cover two popular setups:

完成此操作因您的項目設置而異。 我將介紹兩種流行的設置:

For create-react-app projects, add the following to your package.json:

對于create-react-app項目,將以下內容添加到package.json

"proxy": {        "/.netlify/functions": {        "target": "http://localhost:9000",        "pathRewrite": {            "^/\\.netlify/functions": ""        }    }}

For Gatsby.js projects, add the following to your gatsby-config.js:

對于Gatsby.js項目,將以下內容添加到您的gatsby-config.js

const proxy = require('http-proxy-middleware');...developMiddleware: app => {    app.use(        '/.netlify/functions/',        proxy({            target: 'http://lambda:9000',            pathRewrite: {                '/.netlify/functions/': '',            }        })    );},

For most other projects, you can leverage webpack’s dev server, which has proxy support.

對于大多數其他項目,您可以利用webpack的具有代理支持的dev服務器。

編寫我們的功能 (Writing our function)

Before we get to writing Lambda-specific code, we will first create a generic function to handle most of our logic. This way, our code remains portable beyond Lambda.

在編寫特定于Lambda的代碼之前,我們將首先創建一個通用函數來處理大多數邏輯。 這樣,我們的代碼可移植到Lambda之外。

Let’s create a createComment function:

讓我們創建一個createComment函數:

const contentful = require('contentful-management');const client = contentful.createClient({    accessToken: process.env.CONTENTFUL_CONTENT_MANAGEMENT_ACCESS_TOKEN});
module.exports = function createComment(    body,     authorName,     subjectId,     parentCommentId = null) {
return client.getSpace('my-space-id')        .then(space => space.getEnvironment('master'))        .then(environment => environment.createEntry('comment', {            fields: {                body: {                    'en-US': body                },                author: {                    'en-US': authorName                },                subject: {                    'en-US': subjectId                },                parentComment: {                    'en-US': {                        sys: {                            type: 'Link',                            linkType: 'Entry',                            id: parentCommentId                        }                    }                }            }        }))        .then(entry => entry.publish());};

You can put the above function someplace like a utils directory. It uses the contentful-management npm package to create and publish a new comment entry, and returns a promise. Notice we've specified our management API key as an environment variable. You definitely do not want to hard-code that one. When deploying to Netlify or anywhere else, be sure to check that your environment variables are set.

您可以將上述函數放在utils目錄中。 它使用contentful-management npm包來創建和發布新的評論條目,并返回承諾。 請注意,我們已將管理API密鑰指定為環境變量。 您絕對不想硬編碼那個。 部署到Netlify或其他任何地方時,請確保檢查是否已設置環境變量。

You can get your management access token from the Contentful dashboard at “Space settings” > “API keys” > “Content management tokens” > “Generate personal token”.

您可以從“內容”儀表板的“空間設置”>“ API密鑰”>“內容管理令牌”>“生成個人令牌”獲取管理訪問令牌。

Now, let’s create our Lambda-specific function:

現在,讓我們創建特定于Lambda的函數:

const createComment = require('../utils/createComment');
exports.handler = function (event, context, callback) {
const { body, authorName, subjectId, parentCommentId } = JSON.parse(event.body);
createComment(body, authorName, subjectId, parentCommentId)        .then(entry => callback(null, {            headers: {                'Content-Type': 'application/json'            },            statusCode: 200,            body: JSON.stringify({ message: 'OK' })        }))        .catch(callback);};

Put this function in your Lambda source directory, and name the file with the path you’d want the URL to be, e.g. create-comment.js . This will make your function available at the URL /.netlify/functions/create-comment.

將此函數放在Lambda源目錄中,并用您想要URL的路徑命名文件,例如create-comment.js 。 這將使您的函數可以在URL /.netlify/functions/create-comment

大圖 (The big picture)

To illustrate our complete front-end and back-end setup thus far, I’ve created a create-react-app project that functions as a readily-deployable, fully-functional example.

為了說明到目前為止我們完整的前端和后端設置,我創建了一個create-react-app項目 ,該項目充當易于部署且功能齊全的示例。

Notice that in the example project’s netlify.toml file, there’s a few more lines that you should add to your own file. Command tells Netlify what commands to run to build the project. Publish tells Netlify where to find the static assets ready for deployment once the build is complete. You can read more about this file in Netlify's documentation.

請注意,在示例項目的netlify.toml文件中,應在自己的文件中添加幾行。 Command告訴Netlify運行哪些命令來構建項目。 Publish告訴Netlify,一旦構建完成,就可以在哪里找到準備部署的靜態資產。 您可以在Netlify的文檔中閱讀有關此文件的更多信息。

The example project is also easily cloneable and deployable to your own Netlify account via the convenient deploy button in the README.

通過自述文件中的便捷部署按鈕,示例項目也可以輕松克隆并部署到您自己的Netlify帳戶。

If you’ve been implementing this in your own project instead, head over to the Netlify dashboard and follow their straightforward instructions to set up your repo to deploy.

如果您一直在自己的項目中實施此操作,請轉到Netlify儀表板,并按照其簡單的說明設置要部署的存儲庫。

Once it’s up and running, you’ll be able to start commenting like a boss.

一旦啟動并運行,您就可以像老板一樣發表評論。

(Note: this is just a screenshot, so don’t try clicking on it ^_^)

(注意:這只是一個屏幕截圖,因此請勿嘗試單擊它^ _ ^)

直到下一次 (Until next time)

In Part 2, we’ll cover implementing logged-in commenting, as well as giving our comment box some super-cool text formatting functionality.

在第2部分中,我們將介紹如何實現登錄評論,以及為評論框提供一些超酷的文本格式設置功能。

Thanks for reading! — Shaun

謝謝閱讀! —肖恩

Originally published at shaunasaservice.com.

最初發布在shaunasaservice.com上 。

翻譯自: https://www.freecodecamp.org/news/how-you-can-build-your-own-free-serverless-comment-box-dc9d4f366d12/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394013.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394013.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394013.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[Swift]LeetCode1035.不相交的線 | Uncrossed Lines

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★?微信公眾號&#xff1a;山青詠芝&#xff08;shanqingyongzhi&#xff09;?博客園地址&#xff1a;山青詠芝&#xff08;https://www.cnblogs.com/strengthen/&#xff09;?GitHub地址&a…

BZOJ1054(搜索)

大力搜&#xff0c;狀態用一個16位的數字表示。 1 #include <bits/stdc.h>2 3 using namespace std;4 5 #define rep(i,a,b) for(int i(a); i < (b); i)6 7 const int A 30 1;8 9 struct node{int x, y; } op[A]; 10 struct Nod…

php sql語句過濾,php如何做sql過濾

php如何做sql過濾SQL注入攻擊指的是通過構建特殊的輸入作為參數傳入Web應用程序&#xff0c;而這些輸入大都是SQL語法里的一些組合&#xff0c;通過執行SQL語句進而執行攻擊者所要的操作&#xff0c;其主要原因是程序沒有細致地過濾用戶輸入的數據&#xff0c;致使非法數據侵入…

ajaxfileupload 返回值_ajaxFileUpload上傳文件返回json無法解析

最近做一個文件上傳的功能&#xff0c;還要綁定數據傳輸到后臺&#xff0c;為了不影響前端的體驗&#xff0c;采用ajax發送請求。找了一些資料&#xff0c;網上的用ajaxupload這個插件。但是無論成功還是失敗都是執行的error的回調函數。后臺我采用springmvc返回的json&#xf…

leetcode133. 克隆圖(bfs)

給你無向 連通 圖中一個節點的引用&#xff0c;請你返回該圖的 深拷貝&#xff08;克隆&#xff09;。 圖中的每個節點都包含它的值 val&#xff08;int&#xff09; 和其鄰居的列表&#xff08;list[Node]&#xff09;。 class Node { public int val; public List neighbor…

OSCON上最受歡迎的Docker演講

本文講的是OSCON上最受歡迎的Docker演講&#xff0c;【編者的話】本文介紹了上個月OSCON大會有關Docker最受歡迎的一個分享&#xff1a;真實線上環境的Docker技巧。分享者是一名運維工程師叫Bridget&#xff0c;她所在的公司DramaFever在2013年10月開始在線上環境部署使用Docke…

測試驅動開發 測試前移_測試驅動開發:它是什么,什么不是。

測試驅動開發 測試前移by Andrea Koutifaris由Andrea Koutifaris Test driven development has become popular over the last few years. Many programmers have tried this technique, failed, and concluded that TDD is not worth the effort it requires.在過去的幾年中&…

【C/C++開發】C++庫大全

C特殊限定符(1)--static 當static來修飾類數據成員時&#xff0c;這個類的所有對象都可以訪問它。因為值在內存中持續存在&#xff0c;它可以被對象有效共享。這意味著當一個對象改變static數據成員的值時&#xff0c;就改變了所有對象的這個數據成員的值。 定義一個類: class …

java二維數組水平翻轉,C 語言 利用二維數組實現對輸入的數組進行翻轉

C 語言 利用二維數組實現對輸入的數組進行翻轉(幫助理解對圖像翻轉編輯原理)/*?輸入幾行幾列數字和翻轉方式&#xff0c;如&#xff1a;3 4 0即代表3行4列&#xff0c;左右翻轉&#xff1b;6 5 1即代表6行5列&#xff0c;上下翻轉。輸入示例&#xff1a;3 4 0________________…

lightgbm 保存模型 過大_一個例子讀懂LightGBM的模型文件

機器學習模型的可解釋性是個讓人頭痛的問題。在使用LightGBM模型的肯定對生成的GBDT的結構是好奇的&#xff0c;我也好奇&#xff0c;所以就解析一個LightGBM的模型文件看看&#xff0c;通過這個解析&#xff0c;你可以看懂GBDT的結構。另外&#xff0c;了解模型文件&#xff0…

Oracle Sql 胡亂記

/Oracle查詢優化改寫/ --1、coalesce 返回多個值中&#xff0c;第一個不為空的值 select coalesce(, , s) from dual; --2、order by -----dbms_random.value 生產隨機數,利用隨機數對查詢結果進行隨機排序 select * from emp order by dbms_random.value; --指定查詢結果中的一…

leetcode752. 打開轉盤鎖(bfs)

你有一個帶有四個圓形撥輪的轉盤鎖。每個撥輪都有10個數字&#xff1a; ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ 。每個撥輪可以自由旋轉&#xff1a;例如把 ‘9’ 變為 ‘0’&#xff0c;‘0’ 變為 ‘9’ 。每次旋轉都只能旋轉一個撥輪的一位…

Object Pools 噴泉效果實現

摘錄自&#xff1a;http://catlikecoding.com/unity/tutorials/object-pools/ 工程 效果圖 工程里面有響應的注釋 源碼我就不單獨放出來了

從頭學習計算機網絡_我如何通過從頭開始構建網絡爬蟲來自動進行求職

從頭學習計算機網絡它是如何開始的故事 (The story of how it began) It was midnight on a Friday, my friends were out having a good time, and yet I was nailed to my computer screen typing away.星期五是午夜&#xff0c;我的朋友們出去玩得很開心&#xff0c;但我被釘…

php 動態生成文件,php動態程序生成靜態文件示例

html>{title}{content}tmp.html是模板文件/** 說明&#xff1a;生成靜態頁面,tmp.html是模板文件&#xff0c;news.html是要生成的文件&#xff0c;**///1&#xff0c;先讀取模板中內容$strfile_get_contents(tmp.html);//2&#xff0c;將指定的內容進行替換$title網站標題;…

網管的自我修養-網絡系統

目錄&#xff1a; 序章人際關系工具準備電腦維護網絡系統弱電系統外設相關信息系統服務器相關機房建設其他網管網管&#xff0c;會管網絡才算名副其實。管理一般中小企業的網絡&#xff0c;具備CCNA及以上水平就可以了。 一、規劃 首先要根據公司的人員工位數量、打印機傳真等設…

thinkphp日志泄漏漏洞_ThinkPHP框架被爆任意代碼執行漏洞

昨日ThinkPHP框架被爆出了一個php代碼任意執行漏洞&#xff0c;黑客只需提交一段特殊的URL就可以在網站上執行惡意代碼。ThinkPHP作為國內使用比較廣泛的老牌PHP MVC框架&#xff0c;有不少創業公司或者項目都用了這個框架。不過大多數開發者和使用者并沒有注意到本次漏洞的危害…

leetcode 113. 路徑總和 II(Path Sum II)

目錄 題目描述&#xff1a;示例:解法&#xff1a;題目描述&#xff1a; 給定一個二叉樹和一個目標和&#xff0c;找到所有從根節點到葉子節點路徑總和等于給定目標和的路徑。 說明: 葉子節點是指沒有子節點的節點。 示例: 給定如下二叉樹&#xff0c;以及目標和 sum 22&#x…

VMware下配置固定ip,于本機進行通信。

虛擬機裝好后&#xff0c;會生成虛擬的網絡信息。點開VMware下虛擬網絡編輯器。選擇net模式的記錄會發現設定好的網關及dns。 我們只需要在虛擬機上配好對于的ip 輸入 dns 和網關即可轉載于:https://blog.51cto.com/thlovesky/1967929

leetcode417. 太平洋大西洋水流問題(bfs)

給定一個 m x n 的非負整數矩陣來表示一片大陸上各個單元格的高度。“太平洋”處于大陸的左邊界和上邊界&#xff0c;而“大西洋”處于大陸的右邊界和下邊界。規定水流只能按照上、下、左、右四個方向流動&#xff0c;且只能從高到低或者在同等高度上流動。請找出那些水流既可以…