Same idea as the AWS guide: a small Storage over a bucket, then wire and serve.
1. Install
npm install @xtrable-ltd/nanoesis @google-cloud/storage express
2. Two buckets
A private bucket for editable files, and a public bucket for the published site (serve it through an HTTPS load balancer with Cloud CDN for a custom domain).
3. A Storage over Cloud Storage
// gcs-storage.js
import { Storage as Gcs } from '@google-cloud/storage';
const gcs = new Gcs();
export function bucketStorage(name) {
const bucket = gcs.bucket(name);
return {
async get(key) {
try {
const [buf] = await bucket.file(key).download();
return new Uint8Array(buf);
} catch (e) {
if (e.code === 404) return undefined;
throw e;
}
},
async put(key, bytes) {
await bucket.file(key).save(Buffer.from(bytes));
},
async delete(key) {
await bucket.file(key).delete({ ignoreNotFound: true });
},
async wipe() {
await bucket.deleteFiles({ force: true });
},
async list() {
const [files] = await bucket.getFiles();
return files.map((f) => f.name);
},
};
}
4. Wire the editor
// editor.js
import { createEditor, devNoAuth } from '@xtrable-ltd/nanoesis/editor-api';
import { bucketStorage } from './gcs-storage.js';
const files = bucketStorage(process.env.WORKING_BUCKET);
export const editor = createEditor({
editorFiles: files,
website: bucketStorage(process.env.SITE_BUCKET),
login: devNoAuth(), // swap for real login before going live
enumerate: () => files.list(),
});
5. Serve it on Cloud Run
A small Express app on the port Cloud Run provides. The two routes are identical to every other host.
// server.js
import express from 'express';
import { serveEditorAsset } from '@xtrable-ltd/nanoesis/editor-api';
import { editorDist } from '@xtrable-ltd/nanoesis/editor';
import { editor } from './editor.js';
const toBody = (b) => (b == null ? '' : typeof b === 'string' ? b : Buffer.from(b));
const app = express();
app.use(express.raw({ type: '*/*', limit: '25mb' }));
app.all('/api/*', async (req, res) => {
const r = await editor.handleApi({
method: req.method,
path: req.path,
query: new URL(req.originalUrl, 'http://localhost').searchParams,
getHeader: (n) => req.get(n),
body: async () => new Uint8Array(req.body),
});
res.status(r.status).set(r.headers).send(toBody(r.body));
});
app.get('*', async (req, res) => {
const a = await serveEditorAsset(editorDist, req.path);
res.status(a.status).set(a.headers).send(toBody(a.body));
});
app.listen(process.env.PORT || 8080);
6. Publish
Open the editor, create a page, and press Publish. The built site is written to your site bucket; serve it through your load balancer and Cloud CDN.