Skip to content
This repository was archived by the owner on Dec 12, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"
allow:
- dependency-type: "direct"
versioning-strategy: increase
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Pulse Editor Extension Template
This is a React template which you can use to make your own Pulse Editor extension. It uses Webpack Module Federation to share extensions with Pulse Editor.
## Pulse App Template

This is a React full-stack template which you can use to make your own Pulse Editor app. It uses Webpack Module Federation to share modules with Pulse Editor.

For more information about Pulse Editor core and its ecosystem, visit our official [website](https://pulse-editor.com) and [documentation](https://docs.pulse-editor.com).

## Get Started

### Create Pulse Editor extension app using CLI

Expand Down
74 changes: 45 additions & 29 deletions express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import dotenv from "dotenv";
import livereload from "livereload";
import connectLivereload from "connect-livereload";
import { networkInterfaces } from "os";
import { pipeline, Readable } from "stream";
import { promisify } from "util";

dotenv.config({
quiet: true,
Expand Down Expand Up @@ -50,38 +52,52 @@ app.use((req, res, next) => {
return next();
});

// Serve backend
app.use(
`/${pulseConfig.id}/${pulseConfig.version}/server`,
express.static("dist/server")
);
// Catch backend function calls
app.all(/^\/server-function\/(.*)/, async (req, res) => {
const func = req.params[0];

const url = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
// Convert Express req -> Fetch Request
const request = new Request(url, {
method: req.method,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
headers: req.headers as any,
body: ["GET", "HEAD"].includes(req.method)
? null
: JSON.stringify(req.body),
});

const { loadAndCall } = await import("./preview/backend/load-remote.cjs");
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response = await loadAndCall(
func,
request,
pulseConfig.id,
"http://localhost:3030",
pulseConfig.version
);

const streamPipeline = promisify(pipeline);

// If loadAndCall returns a Response (Fetch API Response)
if (response.body) {
// Convert WHATWG stream to Node.js stream
const nodeStream = Readable.fromWeb(response.body);
// Pipe it directly to Express
await streamPipeline(nodeStream, res);
} else {
res.end();
}
});

if (isPreview) {
/* Preview mode */
app.use(express.static("dist/client"));
app.use("/.server-function", express.static("dist/server"));
app.all(/^\/server-function\/(.*)/, async (req, res) => {
const func = req.params[0];

const url = `${req.protocol}://${req.get("host")}${req.originalUrl}`;

// Convert Express req -> Fetch Request
const request = new Request(url, {
method: req.method,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
headers: req.headers as any,
body: ["GET", "HEAD"].includes(req.method)
? null
: JSON.stringify(req.body),
});

const { loadAndCall } = await import("./dist/preview/backend/index.cjs");
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response = await loadAndCall(func, request);

// If loadAndCall returns a Response (Fetch API Response)
if (response instanceof Response) {
res.status(response.status);
response.headers.forEach((v, k) => res.setHeader(k, v));
res.send(await response.text());
} else {
res.json(response);
}
});

app.listen(3030, "0.0.0.0");
} else if (isDev) {
Expand Down
Loading