พื้นที่เก็บข้อมูลนี้เก็บ BCMS เวอร์ชันโอเพ่นซอร์ส ซึ่งเป็น CMS ไร้หัวสมัยใหม่ที่ช่วยให้คุณจัดการเนื้อหาได้อย่างง่ายดายด้วยโครงสร้างที่ยืดหยุ่น อินเทอร์เฟซที่ใช้งานง่าย ตัวเลือกการใช้งานที่รวดเร็ว ทำให้เหมาะสำหรับนักพัฒนาและทีมที่กำลังมองหาโซลูชัน CMS ที่ปรับแต่งได้
git clone https://github.com/bcms/cms
npm i
docker compose up
http://localhost:8080
หลังจากที่คุณมีเซิร์ฟเวอร์ที่ใช้ Debian แล้ว คุณสามารถใส่ SSH ลงไปได้และทำตามขั้นตอนด้านล่าง
ติดตั้งการอ้างอิงหากคุณยังไม่มีบนเซิร์ฟเวอร์:
sudo apt update && sudo apt install docker.io git nodejs npm
npm i -g n && n 20
เนื่องจากเราใช้แพ็คเกจ GitHub คุณจะต้องเพิ่มการกำหนดค่าให้กับ ~/.npmrc
เพื่อดึงแพ็คเกจ เพิ่มสองบรรทัดต่อไปนี้:
//npm.pkg.github.com/:_authToken=<GITHUB_TOKEN>
@bcms:registry=https://npm.pkg.github.com
หากต้องการสร้าง GITHUB_TOKEN
ให้ทำตามบทช่วยสอนนี้ สิทธิ์เดียวที่จำเป็นสำหรับโทเค็นนี้คือ read:packages
npm i -g @bcms/selfhosted-cli
selfbcms --deploy debian
หลังจากที่คุณมีเซิร์ฟเวอร์ที่ใช้ Debian แล้ว คุณสามารถใส่ SSH ลงไปได้และทำตามขั้นตอนด้านล่าง
sudo apt update && sudo apt install docker.io git
mkdir ~ /bcms
mkdir ~ /bcms/db ~ /bcms/uploads ~ /bcms/backups
git clone https://github.com/bcms/cms
docker build . -t my-bcms
docker network create -d bridge --subnet 10.20.0.0/16 --ip-range 10.20.30.0/24 --gateway 10.20.30.1 bcms-net
หากคุณไม่มี MongoDB คุณสามารถเรียกใช้ภายในคอนเทนเนอร์ Docker บนเซิร์ฟเวอร์เดียวกันได้:
docker run -d --name my-bcms-db -v ~ /bcms/db:/data/db -e MONGO_INITDB_ROOT_USERNAME= < DB_ADMIN_USERNAME > -e MONGO_INITDB_ROOT_PASSWORD= < DB_ADMIN_PASSWORD > --network bcms-net mongo:7
ด้วยการตั้งค่านี้ ฐานข้อมูล MongoDB จะถูกจัดเก็บไว้ใน ~/bcms/db
และสามารถเข้าถึงได้จาก bcms-net
บนพอร์ต 27017
docker run -d --name my-bcms -v ~ /bcms/uploads:/app/backend/uploads -v ~ /bcms/backups:/app/backend/backups -e " DB_URL=<MONGODB_CONNECTION_URL> " --network bcms-net my-bcms
หากตั้งค่า MongoDB บนเซิร์ฟเวอร์เดียวกัน DB_URL
จะเป็น mongodb://<DB_ADMIN_USERNAME>:<DB_ADMIN_PASSWORD>@my-bcms-db:27017/admin
ในการจัดการคำขอที่เข้ามา คุณต้องตั้งค่าพร็อกซีย้อนกลับ Nginx
# File location: ~/bcms/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768 ;
}
http {
sendfile on ;
tcp_nopush on ;
tcp_nodelay on ;
keepalive_timeout 65 ;
types_hash_max_size 2048 ;
server_tokens off ;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on ;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' blob: data:" ;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Referrer-Policy "no-referrer" ;
server {
listen 80 default_server ;
listen [::]:80 default_server ;
server_name _;
client_max_body_size 105G ;
location /api/v4/socket {
proxy_http_version 1.1 ;
proxy_set_header Upgrade $http_upgrade ;
proxy_set_header Connection "upgrade" ;
proxy_pass http://my-bcms:8080/api/v4/socket;
}
location /__plugin {
proxy_read_timeout 60 ;
proxy_connect_timeout 60 ;
proxy_send_timeout 60 ;
proxy_pass http://my-bcms:8080/__plugin;
}
location / {
proxy_read_timeout 60 ;
proxy_connect_timeout 60 ;
proxy_send_timeout 60 ;
proxy_pass http://my-bcms:8080;
}
}
}
การกำหนดค่านี้ใช้โฮสต์เสมือน Nginx เริ่มต้น หากต้องการใช้โดเมนที่กำหนดเอง ให้ปรับการกำหนดค่าตามความจำเป็น
# File location: ~/bcms/proxy.Dockerfile
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
docker build . -f proxy.Dockerfile -t my-bcms-proxy
docker run -d -p 80:80 --name my-bcms-proxy --network bcms-net my-bcms-proxy
เรายินดีรับการมีส่วนร่วม!
ในเดือนกันยายน ปี 2024 เราได้ทำการเปลี่ยนแปลงครั้งใหญ่: BCMS Cloud เข้าสู่ซอร์สแบบปิด (ในชื่อ BCMS Pro) และเวอร์ชันโอเพ่นซอร์สก็กลายเป็นเวอร์ชันสแตนด์อโลนโดยสมบูรณ์
ทำไมเราถึงทำเช่นนี้?
เมื่อเราสร้าง BCMS เป็นครั้งแรก เราได้รวมศูนย์ระบบการตรวจสอบความถูกต้องไว้ใน BCMS Cloud แม้ว่าคุณจะโฮสต์ด้วยตนเอง แต่คุณยังคงต้องเข้าสู่ระบบผ่านระบบของเรา เราคิดว่าสิ่งนี้จะทำให้สิ่งต่างๆ เช่น การเชิญผู้ใช้ การส่งอีเมล และการจัดการการเริ่มต้นใช้งานง่ายขึ้น แต่แล้วผู้คนใน Reddit ก็ฉีกเราออกจากกัน และพวกเขาก็พูดถูก เราก็เลยฟัง
ปัญหาอีกประการหนึ่งคือการทำให้ BCMS อัปเดตอยู่เสมอ เรากำลังปรับปรุงอย่างต่อเนื่อง แต่การทำให้แน่ใจว่าเวอร์ชันที่คุณโฮสต์เองสามารถอัปเดตได้อย่างง่ายดายนั้นเป็นเรื่องที่น่าปวดหัวทางเทคนิคเสมอ
วิธีที่เราตั้งค่า BCMS Cloud ในตอนแรกก็สร้างปัญหาเช่นกัน แต่ละอินสแตนซ์ต้องทำงานบน VPS แยกของตัวเอง ซึ่งทำให้การทำงานช้าลงและทำให้ต้นทุนโครงสร้างพื้นฐานพุ่งสูง
เป้าหมายของเราคือการสร้างประสบการณ์การแก้ไขเนื้อหาที่รวดเร็วและมีเหตุผล แต่การพยายามทำให้ทั้งเวอร์ชันโอเพ่นซอร์สและคลาวด์ก้าวไปข้างหน้าเริ่มรู้สึกว่าไม่ยั่งยืน ดังนั้นเราจึงโทรไปแยกพวกเขา ขณะนี้ชุมชนโอเพ่นซอร์สมีสิ่งที่พวกเขาขอแล้ว: BCMS ที่มีความสมบูรณ์ในตัวเองและโฮสต์ได้เอง ไม่มีค่าใช้จ่ายใด ๆ ทั้งสิ้น
ในขณะเดียวกัน เราจะผลักดันสิ่งใหม่ทั้งหมดต่อไป - BCMS Pro ซึ่งขณะนี้เป็นซอร์สแบบปิด ได้รับการพัฒนาใหม่ตั้งแต่ต้นจนจบ และปรับให้เหมาะสมสำหรับผู้ที่ต้องการประสบการณ์การจัดการระดับพรีเมียม
ทีมหลักของ BCMS มีขนาดเล็กมาก มีเพียงวิศวกรสามคน นักออกแบบหนึ่งคน ผู้จัดการโครงการ และผู้เขียนเนื้อหาหนึ่งคน ดังนั้นเราจึงมุ่งเน้นไปที่ BCMS Pro เกือบทั้งหมด แต่เรารู้สึกตื่นเต้นที่จะได้เห็นว่าชุมชนนำเวอร์ชันโอเพ่นซอร์สไปใช้ที่ไหน
ขอให้มีความสุขในการเขียนโค้ด!
หากคุณมีคำถามหรือต้องการความช่วยเหลือ โปรดอย่าลังเลที่จะเปิดปัญหาหรือติดต่อเราที่ Discord
ติดตามบน X (Twitter)
ติดตามบน LinkedIn
เข้าร่วมกับเราบน Discord
มี 4 วิธีหลักที่คุณสามารถขยาย BCMS ของคุณได้ ได้แก่ กิจกรรม ฟังก์ชัน งาน และปลั๊กอิน 3 รายการแรกมีไว้สำหรับขยายฟังก์ชันแบ็กเอนด์และดำเนินงานแบ็กเอนด์แบบกำหนดเองเท่านั้น ในขณะที่ปลั๊กอินเป็นแอปที่มีแบ็กเอนด์และ UI ของตัวเองที่ด้านบนของคอร์ BCMS
เหตุการณ์ BCMS คือไฟล์ JavaScript แบบกำหนดเอง (ฟังก์ชัน JS) ซึ่งจะดำเนินการเมื่อมีการทริกเกอร์เหตุการณ์ BCMS ภายใน เช่น เมื่อมีการสร้าง อัปเดต หรือลบรายการ หรือเมื่อมีการสร้าง อัปเดต หรือลบวิดเจ็ต รายการประเภทกิจกรรมทั้งหมด
การสร้างตัวจัดการเหตุการณ์นั้นง่ายดายพอ ๆ กับการเพิ่มไดเร็กทอรี root /backend/events
ของไฟล์ ไดเร็กทอรีนี้อยู่ภายในคอนเทนเนอร์ BCMS คุณสามารถเมานต์เป็นโวลุ่มได้เมื่อเรียกใช้คอนเทนเนอร์ และจะมีลักษณะดังนี้: -v <path_to_my_events_dir>:/app/backend/events
หากคุณใช้งาน BCMS แบบโลคัลจากที่เก็บนี้ คุณสามารถเพิ่มไฟล์เหตุการณ์ลงใน /backend/events/<my_event>.{js|ts}
นี่คือตัวอย่างเหตุการณ์ง่ายๆ:
// Is used locally in /backend/events/test.js
const { createEvent } = require ( '@bcms/selfhosted-backend/event' ) ;
module . exports = createEvent ( async ( ) => {
return {
config : {
// Trigger Event handler only for
// Entry changes
scope : 'entry' ,
// Listen for all Event types:
// (create, update, delete)
type : 'all' ,
} ,
// This method will be executed when
// Event is triggered
async handler ( type , scope , data ) {
// Do something with the event
console . log ( { type , scope , data } ) ;
} ,
} ;
} ) ;
ไฟล์นี้จะถูกโหลดโดยแบ็กเอนด์ BCMS และดำเนินการ ซึ่งหมายความว่าไฟล์จะทำงานในขอบเขตเดียวกัน และคุณสามารถใช้ยูทิลิตี้ภายใน เช่น Repo.*
เพื่อเข้าถึงฐานข้อมูลได้ การดำเนินการของไฟล์นี้ไม่มีการจำกัด สิทธิ์ทั้งหมดที่แบ็กเอนด์ BCMS มี กิจกรรมของคุณก็จะมีเช่นกัน มันไม่อันตรายเหรอ? ใช่และไม่ใช่ พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ยิ่งใหญ่ ซึ่งหมายความว่าคุณไม่ควรเรียกใช้โค้ดที่ไม่น่าเชื่อถือภายในกิจกรรม
ตอนนี้ จะเป็นอย่างไรถ้าคุณต้องการนำเข้าโมดูลที่กำหนดเอง เช่น @paralleldrive/cuid2? คุณสามารถทำได้โดยเพิ่มลงใน /backend/custom-package.json
ซึ่งควรมีโครงสร้างดังนี้:
{
"dependencies" : {
// Your custom packages
"@paralleldrive/cuid2" : " ^2.2.2 "
}
}
แพ็คเกจแบบกำหนดเองจะเริ่มต้นได้เมื่อแบ็กเอนด์ BCMS เริ่มทำงาน
มีอีก 1 อย่าง จะเกิดอะไรขึ้นถ้าคุณมีตรรกะร่วมกันระหว่างกิจกรรม งาน และฟังก์ชันของคุณ? เรากำลังเรียกไฟล์เพิ่มเติมเหล่านั้น แต่คุณสามารถดูไฟล์เหล่านั้นเป็นยูทิลิตี้ที่คุณกำหนดเองได้ ภายใน /backend/additional
คุณสามารถเพิ่มไฟล์ JS ใดก็ได้และนำเข้าในกิจกรรม
เช่นเดียวกับเหตุการณ์ BCMS ฟังก์ชัน BCMS คือไฟล์ JavaScript (ฟังก์ชัน JS) ซึ่งจะดำเนินการเมื่อมีการเรียกจุดสิ้นสุดของฟังก์ชัน: POST: /api/v4/function/<my_function_name>
คุณสามารถดูได้เหมือนกับโค้ดที่คุณกำหนดเองซึ่งจะทำงานบนแบ็กเอนด์ BCMS เมื่อมีการร้องขอ HTTP ไปยังจุดสิ้นสุดการดำเนินการของฟังก์ชัน
การสร้างฟังก์ชั่นนั้นง่ายพอ ๆ กับการเพิ่มไฟล์ลงใน /backend/functions
ไดเร็กทอรีนี้อยู่ภายในคอนเทนเนอร์ BCMS คุณสามารถเมานต์เป็นโวลุ่มได้เมื่อเรียกใช้คอนเทนเนอร์ และจะมีลักษณะดังนี้: -v <path_to_my_functions_dir>:/app/backend/functions
หากคุณใช้งาน BCMS แบบโลคัลจากที่เก็บนี้ คุณสามารถเพิ่มไฟล์ Function ไปที่ /backend/functions/<my_function>.{js|ts}
นี่คือตัวอย่างฟังก์ชันง่ายๆ ที่จะสะท้อนคำขอ:
const { createFunction } = require ( '@bcms/selfhosted-backend/function' ) ;
module . exports = createFunction ( async ( ) => {
return {
config : {
name : 'echo' ,
} ,
async handler ( { request } ) {
return {
message : 'Function echo' ,
data : request . body ,
} ;
} ,
} ;
} ) ;
หากต้องการเรียกใช้ฟังก์ชันนี้ให้สำเร็จ คุณจะต้องสร้างคีย์ Api ( Administration/Key manager ) และอนุญาตให้เรียกใช้ฟังก์ชันได้ หลังจากนั้นคุณสามารถสร้างคำขอ HTTP ได้:
POST http://localhost:8080/api/v4/function/echo
Content-Type: application/json
Authorization: ApiKey <key_id>.<key_secret>
{
"fromClient" : " Hey from client "
}
// Response
// {
// "success": true,
// "result": {
// "message": "Function echo",
// "data": {
// "fromClient": "Hey from client"
// }
// }
// }
ไฟล์นี้จะถูกโหลดโดยแบ็กเอนด์ BCMS และดำเนินการ ซึ่งหมายความว่าไฟล์จะทำงานในขอบเขตเดียวกัน และคุณสามารถใช้ยูทิลิตี้ภายใน เช่น Repo.*
เพื่อเข้าถึงฐานข้อมูลได้ การดำเนินการของไฟล์นี้ไม่มีการจำกัด สิทธิ์ทั้งหมดที่แบ็กเอนด์ BCMS มี ฟังก์ชันของคุณก็จะมีเช่นกัน มันไม่อันตรายเหรอ? ใช่และไม่ใช่ พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ยิ่งใหญ่ ซึ่งหมายความว่าคุณไม่ควรเรียกใช้โค้ดที่ไม่น่าเชื่อถือภายในฟังก์ชัน
ตอนนี้ จะเป็นอย่างไรถ้าคุณต้องการนำเข้าโมดูลที่กำหนดเอง เช่น @paralleldrive/cuid2? คุณสามารถทำได้โดยเพิ่มลงใน /backend/custom-package.json
ซึ่งควรมีโครงสร้างดังนี้:
{
"dependencies" : {
// Your custom packages
"@paralleldrive/cuid2" : " ^2.2.2 "
}
}
แพ็คเกจแบบกำหนดเองจะเริ่มต้นได้เมื่อแบ็กเอนด์ BCMS เริ่มทำงาน
มีอีก 1 อย่าง จะเกิดอะไรขึ้นถ้าคุณมีตรรกะร่วมกันระหว่างกิจกรรม งาน และฟังก์ชันของคุณ? เรากำลังเรียกไฟล์เพิ่มเติมเหล่านั้น แต่คุณสามารถดูไฟล์เหล่านั้นเป็นยูทิลิตี้ที่คุณกำหนดเองได้ ภายใน /backend/additional
คุณสามารถเพิ่มไฟล์ JS ใดก็ได้และนำเข้าใน Function
เช่นเดียวกับเหตุการณ์และฟังก์ชัน BCMS งาน BCMS คือไฟล์ JavaScript (ฟังก์ชัน JS) ซึ่งดำเนินการในช่วงเวลา CRON ที่ระบุ คุณสามารถดูได้เหมือนกับโค้ดที่คุณกำหนดเองซึ่งจะทำงานบนแบ็กเอนด์ BCMS ในช่วงเวลาที่กำหนด
การสร้างงานนั้นง่ายดายเพียงแค่เพิ่มไฟล์ลงใน /backend/jobs
ไดเร็กทอรีนี้อยู่ภายในคอนเทนเนอร์ BCMS คุณสามารถเมานต์เป็นโวลุ่มได้เมื่อเรียกใช้คอนเทนเนอร์ และจะมีลักษณะดังนี้: -v <path_to_my_jobs_dir>:/app/backend/jobs
หากคุณใช้งาน BCMS แบบโลคัลจากที่เก็บนี้ คุณสามารถเพิ่มไฟล์งานลงใน /backend/jobs/<my_job>.{js|ts}
นี่คือตัวอย่างฟังก์ชันง่ายๆ ที่จะบันทึกเวลาปัจจุบันของคอนโซลทุกๆ นาที:
const { createJob } = require ( '@bcms/selfhosted-backend/job' ) ;
module . exports = createJob ( async ( ) => {
return {
cronTime : '* * * * *' , // You can use: https://crontab.guru/
async handler ( ) {
console . log ( new Date ( ) . toISOString ( ) ) ;
} ,
} ;
} ) ;
ไฟล์นี้จะถูกโหลดโดยแบ็กเอนด์ BCMS และดำเนินการ ซึ่งหมายความว่าไฟล์จะทำงานในขอบเขตเดียวกัน และคุณสามารถใช้ยูทิลิตี้ภายใน เช่น Repo.*
เพื่อเข้าถึงฐานข้อมูลได้ การดำเนินการของไฟล์นี้ไม่จำกัด การอนุญาตทั้งหมดที่แบ็กเอนด์ BCMS มี งานของคุณก็จะมีเช่นกัน มันไม่อันตรายเหรอ? ใช่และไม่ใช่ พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ยิ่งใหญ่ ซึ่งหมายความว่าคุณไม่ควรเรียกใช้โค้ดที่ไม่น่าเชื่อถือภายในงาน
ตอนนี้ จะเป็นอย่างไรถ้าคุณต้องการนำเข้าโมดูลที่กำหนดเอง เช่น @paralleldrive/cuid2? คุณสามารถทำได้โดยเพิ่มลงใน /backend/custom-package.json
ซึ่งควรมีโครงสร้างดังนี้:
{
"dependencies" : {
// Your custom packages
"@paralleldrive/cuid2" : " ^2.2.2 "
}
}
แพ็คเกจแบบกำหนดเองจะเริ่มต้นได้เมื่อแบ็กเอนด์ BCMS เริ่มทำงาน
มีอีก 1 อย่าง จะเกิดอะไรขึ้นถ้าคุณมีตรรกะร่วมกันระหว่างกิจกรรม งาน และฟังก์ชันของคุณ? เรากำลังเรียกไฟล์เพิ่มเติมเหล่านั้น แต่คุณสามารถดูไฟล์เหล่านั้นเป็นยูทิลิตี้ที่คุณกำหนดเองได้ ภายใน /backend/additional
คุณสามารถเพิ่มไฟล์ JS ใดก็ได้และนำเข้าในงาน
คุณสามารถดูปลั๊กอิน BCMS เป็นแอปพลิเคชันที่มีแบ็กเอนด์และฟรอนต์เอนด์ของตัวเอง ซึ่งให้บริการโดยแบ็กเอนด์ BCMS และสามารถเข้าถึงคุณลักษณะแบ็กเอนด์และฟรอนต์เอนด์ทั้งหมดได้ สำหรับแบ็คเอนด์ปลั๊กอิน คุณต้องปฏิบัติตามรูปแบบบางอย่าง แต่สำหรับ Plugin UI คุณสามารถสร้างแอปพลิเคชัน SPA ใดก็ได้ (คุณสามารถใช้ React หรือ VanillaJS ได้ แต่เราขอแนะนำ VueJS เนื่องจากคุณจะสามารถใช้ BCMS UI Components ได้)
วิธีที่ดีที่สุดในการอธิบายเรื่องนี้คือการยกตัวอย่างง่ายๆ ให้กับคุณ นี่จะเป็นโครงสร้างของปลั๊กอิน:
/backend/plugins
- /hello-world
- /_ui
- index.html
- config.json
- controller.js
- main.js
เพื่อให้ตัวอย่างนี้ง่ายที่สุดเท่าที่จะเป็นไปได้ โค้ดส่วนหน้าทั้งหมดจะอยู่ใน _ui/index.html
ในขณะที่แบ็กเอนด์จะมีตัวควบคุม 1 ตัวซึ่งจะทักทายผู้ใช้
config.json
{
"version" : " 1 " ,
"dependencies" : {}
}
คอนโทรลเลอร์.js
const { createPluginController } = require ( '@bcms/selfhosted-backend/plugin' ) ;
const { createControllerMethod } = require ( '@bcms/selfhosted-backend/_server' ) ;
const {
RP ,
} = require ( '@bcms/selfhosted-backend/security/route-protection/main' ) ;
exports . HelloWorldController = createPluginController ( {
name : 'NameGreet' ,
path : '/greet' ,
methods ( ) {
return {
greet : createControllerMethod ( {
path : '/:name' ,
type : 'get' ,
preRequestHandler : RP . createJwtCheck ( ) ,
async handler ( { request } ) {
const params = request . params ;
return {
greet : `Hello ${ params . name } !` ,
} ;
} ,
} ) ,
} ;
} ,
} ) ;
main.js
const { createPlugin } = require ( '@bcms/selfhosted-backend/plugin' ) ;
const { HelloWorldController } = require ( './controller' ) ;
module . exports = createPlugin ( async ( ) => {
return {
id : 'hello-world' ,
name : 'Hello World' ,
controllers : [ HelloWorldController ] ,
middleware : [ ] ,
async policy ( ) {
return [
{
name : 'Full access' ,
} ,
] ;
} ,
} ;
} ) ;
_ui/index.html
<!DOCTYPE html >
< html lang =" en " >
< head >
< meta charset =" UTF-8 " />
< title > Hello world </ title >
< style >
body {
color: white;
}
</ style >
</ head >
< body >
< h1 > Hello world </ h1 >
< div >
< input id =" greet-input " placeholder =" Greet " type =" text " />
< button onclick =" greet(this) " > Send </ button >
< div id =" greet-result " > </ div >
</ div >
< h2 > List of templates </ h2 >
< div id =" templates " > </ div >
< script >
async function onLoad ( ) {
const templates =
await window . parent . bcms . sdk . template . getAll ( ) ;
const el = document . getElementById ( 'templates' ) ;
if ( el ) {
el . innerHTML = `<pre> ${ JSON . stringify (
templates ,
null ,
4 ,
) } </pre>` ;
}
window . removeEventListener ( 'load' , onLoad ) ;
}
window . addEventListener ( 'load' , onLoad ) ;
async function greet ( ) {
const inputEl = document . getElementById ( 'greet-input' ) ;
const value = inputEl . value ;
const result = await window . parent . bcms . sdk . send ( {
url : `/api/v4/plugin/hello-world/greet/ ${ value } ` ,
} ) ;
const el = document . getElementById ( 'greet-result' ) ;
el . innerHTML = `<pre> ${ JSON . stringify ( result , null , 4 ) } </pre>` ;
}
</ script >
</ body >
</ html >
สิ่งที่ต้องทำ: อธิบายปลั๊กอินโดยละเอียดและสร้างตัวอย่างปลั๊กอิน