UNPKG

adonisjs-livewire

Version:

A front-end framework for AdonisJS

103 lines (102 loc) 4.26 kB
import { fsReadAll, slash } from '@adonisjs/core/helpers'; import { importDefault } from '@poppinss/utils'; import { basename, extname, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; import edge from 'edge.js'; import { edgeTags } from 'edge-tags'; const JS_MODULES = ['.js', '.cjs', '.mjs']; export default class ViewProvider { app; constructor(app) { this.app = app; } /** * The container bindings have booted */ async boot() { const viewComponents = {}; const viewComponentFiles = await fsReadAll(this.app.relativePath('app/components'), { pathType: 'url', ignoreMissingRoot: true, filter: (filePath) => { const ext = extname(filePath); if (basename(filePath).startsWith('_')) { return false; } if (JS_MODULES.includes(ext)) { return true; } if (ext === '.ts' && !filePath.endsWith('.d.ts')) { return true; } return false; }, }); for (let file of viewComponentFiles) { if (file.endsWith('.ts')) { file = file.replace(/\.ts$/, '.js'); } const relativeFileName = slash(relative(this.app.relativePath('app/components'), fileURLToPath(file))); const componentClass = (await importDefault(() => import(file), relativeFileName)); const componentName = relativeFileName.replace(/\.js$/, ''); viewComponents[componentName] = componentClass; } async function renderViewComponent(name, { $props, $slots, $caller } = {}) { if (typeof name === 'string' && !(name in viewComponents)) { return `Component ${name} not found`; } // @ts-ignore const component = typeof name === 'string' ? new viewComponents[name]($props.all()) : name; const renderer = edge.createRenderer(); component.$props = $props; component.$slots = $slots; component.$caller = $caller; let data = {}; let prototype = Object.getPrototypeOf(component); while (prototype && prototype !== Object.prototype) { const props = Object.getOwnPropertyNames(prototype); for (const prop of props) { if (['constructor', 'render'].includes(prop)) { continue; } const descriptor = Object.getOwnPropertyDescriptor(prototype, prop); if (descriptor && (descriptor.get || descriptor.set)) { data = Object.assign(data, { get [prop]() { return component[prop]; }, }); } else if (typeof component[prop] === 'function') { data[prop] = component[prop].bind(component); } else { data[prop] = component[prop]; } } prototype = Object.getPrototypeOf(prototype); } for (const key of Object.keys(component)) { data[key] = component[key]; } for (const key of Object.keys($props || {})) { data[key] = $props[key]; } data['$slots'] = $slots; data['$props'] = $props; data['$caller'] = $caller; renderer.share(data); component.view = renderer; return await renderer.renderRaw(await component.render()); } edge.global('renderViewComponent', renderViewComponent); //@ts-ignore this.app.container.bindValue('renderViewComponent', renderViewComponent); for (const key of Object.keys(viewComponents)) { edge.registerTemplate(key, { template: `{{{ await renderViewComponent("${key}", { $props, $slots, $caller }) }}}`, }); } edge.use(edgeTags); } }