방법 1 (핵심 코드 수정)
나는 추가 도우미와 함께 Ghost의 소스 코드를 확장 할 수 있음을 발견했습니다. Current/Core/Frontend/Apps에 새 디렉토리를 추가하여이를 달성했습니다. 나는 코드가 매우 간단한 Amp라는 기존의 "앱"의 예를 사용하여 테마에서 사용할 수있는 새 헬퍼를 만들기 시작했습니다. 이 기존 앱에서는 도우미가 lib/helpers에 등록되어 있기 때문에 구조는 간단합니다. 프로세스가 끝나면 앱에서 앱의 디렉토리 이름을 apps.internal json 섹션에서
의 앱에 현재/core/shared/config/rements.json에 추가해야합니다.const path = require ( 'path'); module.exports = { 활성화 : 기능 활성화 (고스트) { ghost.helperservice.registerdir (path.resolve (__ dirname, './lib/helpers')); } };
다음,이 앱의 lib 디렉토리에서 우리는 Helpers라는 폴더를 만듭니다. 내부에는 새 파일을 만듭니다. 핸들 바 템플릿에서 호출 할 도우미 이름이됩니다. 예를 들어, 대문자 이름을 지정하자.
const path = require('path'); module.exports = { activate: function activate(ghost) { ghost.helperService.registerDir(path.resolve(__dirname, './lib/helpers')); } };
const {safestring, escapeexpression} = 요구 사항 ( '../../../../ 서비스/핸들 바'); module.exports = 함수 대문자 (텍스트) { `$ {text.toupperCase ()}`; };
응용 프로그램 디렉토리의 이름을 current/core/shared/config/remerides.json에 추가하는 것을 잊지 마십시오. 유령을 다시 시작한 후 모든 것이 준비되어야합니다.
const {SafeString, escapeExpression} = require('../../../../services/handlebars'); module.exports = function uppercase(text) { return `${text.toUpperCase()}`; };
나는 최근 에이 방법을 개발했으며, 자체 주최 유령뿐만 아니라 호스팅 제공 업체가 제공하는 유령 인스턴스에도 적용 할 수 있습니다. 후자의 경우, 최종 유령 인스턴스의 프록시 역할을하는 적절한 아키텍처 계획과 작은 서버를 구매해야합니다.
nginx 서버 ← node.js 미들웨어 ← 고스트 인스턴스
사용자의 브라우저는 미들웨어의 업스트림이 포함 된 Nginx 서버에 요청을 보냅니다. 위치에 관계없이 모든 요청은 미들웨어로 프록시됩니다.
미들웨어는 express-http-proxy (https://github.com/villadora/express-http-proxy) 라이브러리가있는 Node.js에서 실행되는 Express 서버입니다. Ghost 인스턴스와 통신하도록 프록시를 구성합니다. Express-HTTP-Proxy Library에는 "프록시 서버의 응답을 장식하는 데 사용할 수있는 USERRESDEDECORATOR 속성이 있습니다. 간단히 말해서, 우리는 사용자의 브라우저로 보내기 전에 고스트의 응답을 수정할 수 있습니다.
우리의 userresdecorator는 기본 스레드를 차단하지 않도록 비동기식이 될 것입니다. 도우미를 만들 때 비동기 처리 주제로 돌아갑니다. 현재로서는 사용자의 브라우저 요청이 장식되어야하는 모든 것이 아니라는 것을 알아야합니다. 따라서 첫 번째 단계는 고스트의 응답의 내용 유형 헤더를 확인하는 것입니다. 이 작업을 다음과 같이 수행 한 다음 텍스트/html인지 비교하여 사용자에게 반환 된 HTML 문서 만 장식하십시오 :
// 여기서 'proxyres'는 'Userresdecorator'내에서 대리 응답입니다. const contenttype = proxyres.headers
|| '';;
if (! contenttype.includes ( 'text/html')) {
// 응답이 '텍스트/html'이 아닌 경우 원본 콘텐츠를 반환합니다.
반환 proxyresdata;
}
htmlcontent = proxyresdata.toString ( 'utf8');
// 'htmlContent'로 무언가를하고 반환합니다
반환 htmlcontent;
// Where 'proxyRes' is your proxy response inside 'userResDecorator' const contentType = proxyRes.headers['content-type'] || ''; if (!contentType.includes('text/html')) { // Return original content if response is not 'text/html' return proxyResData; } let htmlContent = proxyResData.toString('utf8'); // Do something with 'htmlContent' and return return htmlContent;이 기사에서는 테마의 index.hbs 파일 (홈페이지)에서 사용자 정의 도우미를 만들 것입니다. 핸들 바 템플릿의 보이는 위치에서, 나는 예제 사용자 정의 도우미를 추가하여 {{hello_world}}.
]️ 그런 다음 홈페이지의 눈에 보이는 지점에 배치하지만 고스트 페이지를 새로 고침 할 때 어떤 일이 발생하는지 확인하십시오!
{{!
새로 고침 후 {{hello_world}} 도우미가 고스트의 기본 도우미에 존재하지 않기 때문에 고스트로부터 오류 메시지가 나타납니다. 우리의 논리가 작동하려면, 우리는이 헬퍼가 고스트의 내장 핸들 바에 의해 도우미로 취급되지 않도록이 헬퍼를 피해야합니다.
{{!After refreshing, I get an error message from Ghost because the {{hello_world}} helper doesn’t exist in Ghost's default helpers. For our logic to work, we must escape this helper so that it’s not treated as a helper by Ghost’s built-in Handlebars.
The correct way is to write this helper as \{{hello_world}}. This way, Ghost treats it as plain text. After refreshing the Ghost homepage, you should see the plain text {{hello_world}}. If this happens, you are on the right track. Let’s now return to the middleware server file, where we will use the response decorator.
⚠️ Remember to escape custom helpers in your theme! Don’t forget to add the \ character.
let htmlContent = proxyResData.toString('utf8');// 핸들 바로 응답 html을 컴파일하고 렌더링 된 템플릿을 반환합니다. htmlcontent = proxyresdata.toString ( 'utf8'); const template = handlebars.compile (htmlcontent); htmlcontent = 템플릿 ({});
우와! 이제 핸들 바 등을 사용하여 HTML을 컴파일하고 렌더링했습니다. 그러나 아직 완료되지 않았습니다. 우리는 여전히 사용자 정의 도우미 {{hello_world}}를 등록해야합니다. 다음 코드를 추가하십시오. 바람직하게는 HandleBars.js를 초기화 한 후 :
// Compile response HTML with Handlebars, and return rendered template let htmlContent = proxyResData.toString('utf8'); const template = handlebars.compile(htmlContent); htmlContent = template({});// '미들웨어에서 hello!' 현재 타임 스탬프로 handleBars.registerHelper ( 'hello_world', function (옵션) { ````미들웨어에서. $ {new date (). toisostring ()}`; });
미들웨어 서버를 다시 시작하고 위의 도우미를 등록한 후에는 브라우저에서 렌더링 된 도우미가 헬퍼와 현재 날짜와 시간에 반환 한 텍스트와 함께 렌더링 된 도우미를 볼 수 있습니다.
// Where 'proxyRes' is your proxy response inside 'userResDecorator' const contentType = proxyRes.headers['content-type'] || ''; if (!contentType.includes('text/html')) { // Return original content if response is not 'text/html' return proxyResData; } let htmlContent = proxyResData.toString('utf8'); // Do something with 'htmlContent' and return return htmlContent;이 단계에서는 추가 사용자 정의 도우미로 고스트 테마를 확장 할 수 있습니다.보안
어느 시점에서, 당신은 당신의 도우미들과 다양한 것들을 반환하고 싶을 수도 있습니다. 기본적으로 라이브러리는 XSS 공격으로부터 보호되지만 Safestring 방법을 사용하면이 보호 기능이 작동하지 않습니다. 가능할 때마다 사용하지 마십시오.
또 다른 것! 사용자가 게시물 아래 주석 섹션에 그러한 도우미를 추가하고 매개 변수에 악의적 인 컨텐츠를 추가한다고 상상해보십시오. 보안을 염두에 두십시오. 예를 들어, 모든 HTML을 완전히 렌더링하면 XSS 공격에 취약 할 수 있습니다. 특정 폐쇄 영역에서 핸들 바 등을 컴파일하고 렌더링하는 것이 좋습니다. HTML을 구문 분석하고 필요한 경우 렌더링 핸들 바에 cheerio (https://cheerio.js.org/) 라이브러리를 사용할 수 있습니다. 다음은 이전 렌더링 코드를 수정하여 자신을 보호 할 수있는 방법의 예입니다.
//
내부에서만 핸들 바를 렌더링합니다이 코드에서는 사용자 정의 도우미와 핸들 바가
컨테이너 내에서만 렌더링됩니다.
비동기 처리// Render handlebars only insidewith>In this code, our custom helpers and Handlebars are rendered only within a
container with>Asynchronous Processing
If you intend to create dynamic helpers that return more complex data, you’ll probably need to implement asynchronous helpers in Handlebars over time. This is useful in cases like:
- Fetching values from a database (e.g., Ghost database)
- Sending API requests and processing their responses
You can use an extension called handlebars-async-helpers (https://www.npmjs.com/package/handlebars-async-helpers) for this purpose. It enables asynchronous operations in Handlebars.js, making potentially lengthy and dynamic tasks possible. Here’s a simple example of how you can implement asynchronous processing in your middleware:
// Register async helpers with Handlebars const hb = asyncHelpers(handlebars); hb.registerHelper('hello_world', async function (options) { // You can use await's here! // ... });예를 들어 현재 게시물을 가져 오기 위해 Ghost에서 데이터베이스 쿼리를 만들려면 가능하고 어렵지 않습니다. 명확하고 빠른 SQL 쿼리 빌더 인 Knex (https://knexjs.org/)와 같은 라이브러리를 사용할 수 있습니다. 이를 위해서는 핸들 바 -async helpers가 필요합니다. Ghost의 데이터베이스에 연결하려면 Knex를 올바르게 구성하십시오.
KNEX를 DB 변수로 초기화하고 다음 코드를 시도하십시오.
// 데이터베이스에서 현재 게시물 제목을 반환합니다 hb.registerhelper ( 'post_title', 비동기 함수 (옵션) { const uuid = 옵션 .hash.uuid; 노력하다 { const {title} = db ( "게시물") .select ( "제목") .Where ( "uuid", uuid) .limit (1) .첫 번째(); 리턴 제목; } catch (error) {return`error : $ {error.message}`; } });
그런 다음 Ghost 테마의 Post.hbs 템플릿에서 다음 도우미를 추가하십시오. \ {{post_title uuid = "{{uuid}}"}}. 이 예에서 {{uuid}}는 검색되어 고스트로 이용할 수있는 도우미로 전달되어 도우미의 uuid 필드를 채우고 사용자 정의 도우미가 게시물 제목을 표시하게합니다.// Return current post title from database hb.registerHelper('post_title', async function (options) { const uuid = options.hash.uuid; try { const { title } = await db("posts") .select("title") .where("uuid", uuid) .limit(1) .first(); return title; } catch (error) { return `Error: ${error.message}`; } });성능
미들웨어 기반 솔루션이 속도 측면에서 최고가 아닐 수도 있지만 개인적 으로이 솔루션을 사용하고 페이지로드 시간이 크게 줄어드는 것을 보지 못했습니다. 단일 요청의 평균 응답 시간은 100ms 미만 (Express-Status-Monitor에 따라)이었으며 모든 페이지의 데이터베이스에서 일부 값을 검색하는 사용자 정의 도우미를 사용합니다.
물론, Caching 메커니즘을 추가하여 미들웨어 성능을 향상 시키거나 Express-HTTP-Proxy 대신 대체 솔루션을 사용할 수 있습니다.
아키텍처 구현
Docker 또는 다른 컨테이너화 메커니즘을 사용하십시오. 나는 프로젝트에서 그것을 사용했고 훌륭하게 작동합니다. Ghost, Nginx 및 Node.js 이미지의 고스트 및 데이터베이스 이미지를 추가하십시오. 공유 네트워크 (드라이버 : 브리지)에 연결하고 Nginx 및 Node.js 서버를 구성하여 모두 매우 간단합니다!
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3