@roots/bud-server
Version:
Development server for @roots/bud
198 lines (197 loc) • 6.36 kB
JavaScript
import { __decorate } from "tslib";
import { Service } from '@roots/bud-framework/service';
import { inject } from '@roots/bud-server/inject';
import { bind } from '@roots/bud-support/decorators/bind';
import { BudError } from '@roots/bud-support/errors';
/**
* {@link BudServer}
*/
export class Server extends Service {
/**
* {@link BudServer.appliedMiddleware}
*/
appliedMiddleware = {};
/**
* {@link BudServer.proxyUrl}
* @readonly
*/
get proxyUrl() {
return this.app.hooks.filter(`dev.proxyUrl`, new URL(`http://0.0.0.0`));
}
/**
* {@link BudServer.publicProxyUrl}
* @readonly
*/
get publicProxyUrl() {
return this.app.hooks.filter(`dev.publicProxyUrl`, this.proxyUrl);
}
/**
* {@link BudServer.publicUrl}
* @readonly
*/
get publicUrl() {
return this.app.hooks.filter(`dev.publicUrl`, this.url);
}
/**
* {@link BudServer.url}
* @readonly
*/
get url() {
const url = this.app.hooks.filter(`dev.url`, new URL(`http://0.0.0.0:3000`));
if (this.app.context.port)
url.port = this.app.context.port;
return url;
}
/**
* {@link BudServer.applyMiddleware}
*/
async applyMiddleware() {
await Promise.all(Object.entries(this.enabledMiddleware).map(async ([key, signifier]) => {
if (this.app.context.hot === false && key === `hot`) {
this.logger
.scope(this.app.label, `server`, `middleware`, key)
.log(`disabled`, `bud.context.hot is false`);
return;
}
/** import middleware */
const { factory } = await this.app.module
.import(signifier, import.meta.url)
.catch(this.catch);
/** save reference to middleware instance */
Object.defineProperty(this.appliedMiddleware, key, {
value: factory(this.app),
});
if (typeof this.appliedMiddleware[key] !== `function`) {
this.logger
.scope(this.app.label, `server`, `middleware`, key)
.log(`unused`);
return;
}
this.logger
.scope(this.app.label, `server`, `middleware`, key)
.log(`applied`)
.info(this.appliedMiddleware[key]);
/** apply middleware */
this.application.use(this.appliedMiddleware[key]);
})).catch(this.catch);
}
/**
* {@link Contract.catch}
*/
catch(error) {
throw error;
}
/**
* {@link BudServer.compilerBefore}
*/
async compilerBefore(bud) {
await this.setConnection();
await this.injectScripts();
}
/**
* {@link BudServer.enabledMiddleware}
* @readonly
*/
get enabledMiddleware() {
return this.app.hooks.filter(`dev.middleware.enabled`, [])?.reduce((enabled, key) => ({
...enabled,
[key]: this.availableMiddleware?.[key],
}), {});
}
/**
* {@link BudServer.injectScripts}
*/
async injectScripts() {
if (!this.app.isDevelopment)
return;
const injectOn = async (instance) => inject(instance, Array.from(this.app.hooks.filter(`dev.client.scripts`) ?? []));
this.app.hasChildren
? Object.values(this.app.children).map(injectOn)
: injectOn(this.app);
}
/**
* {@link BudServer.register}
*/
async register(bud) {
if (!bud.isDevelopment)
return;
this.availableMiddleware = {
cookie: ` /bud-server/middleware/cookie`,
dev: ` /bud-server/middleware/dev`,
hot: ` /bud-server/middleware/hot`,
proxy: ` /bud-server/middleware/proxy`,
};
this.application = await bud.module
.import(` /bud-support/express`, import.meta.url)
.then(app => app());
this.logger.log(`server.application`, this.application?.constructor.name);
this.watcher = await import(` /bud-server/server/watcher`).then(({ Watcher }) => new Watcher(() => bud));
this.logger.log(`server.watcher`, this.watcher?.constructor.name);
bud.hooks.on(`dev.client.scripts`, await import(` /bud-server/hooks`)
.catch(this.catch)
.then(result => result?.devClientScripts.callback));
this.application.set(`x-powered-by`, false);
}
/**
* {@link BudServer.run}
*/
async run() {
if (this.app.context.dry === true)
return;
await this.app.hooks.fire(`server.before`, this.app).catch(this.catch);
await this.connection.createServer(this.application).catch(this.catch);
await this.connection.listen();
await this.app.hooks.fire(`server.after`, this.app).catch(this.catch);
}
/**
* {@link BudServer.serverBefore}
*/
async serverBefore(bud) {
await this.setConnection();
await this.injectScripts();
await bud.compiler.compile(bud);
await this.applyMiddleware();
await this.watcher.watch();
}
/**
* {@link BudServer.setConnection}
*/
async setConnection(connection) {
if (connection) {
this.connection = connection;
return this.connection;
}
const isHttps = this.url.protocol === `https:`;
this.connection = await this.app.module
.import(isHttps
? ` /bud-server/server/https`
: ` /bud-server/server/http`, import.meta.url)
.then(({ Server }) => new Server(this.app))
.catch(this.catch);
return this.connection;
}
}
__decorate([
bind
], Server.prototype, "applyMiddleware", null);
__decorate([
bind
], Server.prototype, "catch", null);
__decorate([
bind
], Server.prototype, "compilerBefore", null);
__decorate([
bind
], Server.prototype, "injectScripts", null);
__decorate([
bind
], Server.prototype, "register", null);
__decorate([
bind
], Server.prototype, "run", null);
__decorate([
bind
], Server.prototype, "serverBefore", null);
__decorate([
bind
], Server.prototype, "setConnection", null);