UNPKG

@adonisjs/inertia

Version:

Official Inertia.js adapter for AdonisJS

311 lines (304 loc) 10.7 kB
// configure.ts import string from "@poppinss/utils/string"; // stubs/main.ts import { getDirname } from "@poppinss/utils"; var stubsRoot = getDirname(import.meta.url); // configure.ts var ADAPTERS = ["vue", "react", "svelte", "solid"]; var ADAPTERS_INFO = { vue: { stubFolder: "vue", appExtension: "ts", componentsExtension: "vue", dependencies: [ { name: "@inertiajs/vue3", isDevDependency: false }, { name: "vue", isDevDependency: false }, { name: "@vitejs/plugin-vue", isDevDependency: true } ], ssrDependencies: [{ name: "@vue/server-renderer", isDevDependency: false }], viteRegister: { pluginCall: "vue()", importDeclarations: [{ isNamed: false, module: "@vitejs/plugin-vue", identifier: "vue" }] }, ssrEntrypoint: "inertia/app/ssr.ts" }, react: { stubFolder: "react", appExtension: "tsx", componentsExtension: "tsx", dependencies: [ { name: "@inertiajs/react", isDevDependency: false }, { name: "react", isDevDependency: false }, { name: "react-dom", isDevDependency: false }, { name: "@vitejs/plugin-react", isDevDependency: true }, { name: "@types/react", isDevDependency: true }, { name: "@types/react-dom", isDevDependency: true } ], viteRegister: { pluginCall: "react()", importDeclarations: [{ isNamed: false, module: "@vitejs/plugin-react", identifier: "react" }] }, ssrEntrypoint: "inertia/app/ssr.tsx" }, svelte: { stubFolder: "svelte", appExtension: "ts", componentsExtension: "svelte", dependencies: [ { name: "@inertiajs/svelte", isDevDependency: false }, { name: "svelte", isDevDependency: false }, { name: "@sveltejs/vite-plugin-svelte", isDevDependency: true } ], viteRegister: { pluginCall: "svelte()", ssrPluginCall: "svelte({ compilerOptions: { hydratable: true } })", importDeclarations: [ { isNamed: true, module: "@sveltejs/vite-plugin-svelte", identifier: "svelte" } ] }, ssrEntrypoint: "inertia/app/ssr.ts" }, solid: { stubFolder: "solid", appExtension: "tsx", componentsExtension: "tsx", dependencies: [ { name: "solid-js", isDevDependency: false }, { name: "inertia-adapter-solid", isDevDependency: false }, { name: "vite-plugin-solid", isDevDependency: true }, { name: "@solidjs/meta", isDevDependency: false } ], viteRegister: { pluginCall: "solid()", ssrPluginCall: "solid({ ssr: true })", importDeclarations: [{ isNamed: false, module: "vite-plugin-solid", identifier: "solid" }] }, ssrEntrypoint: "inertia/app/ssr.tsx" } }; async function defineExampleRoute(command, codemods) { const tsMorph = await codemods.getTsMorphProject(); const routesFile = tsMorph?.getSourceFile(command.app.makePath("./start/routes.ts")); if (!routesFile) { return command.logger.warning("Unable to find the routes file"); } const action = command.logger.action("update start/routes.ts file"); try { routesFile?.addStatements((writer) => { writer.writeLine(`router.on('/').renderInertia('home')`); }); await tsMorph?.save(); action.succeeded(); } catch (error) { codemods.emit("error", error); action.failed(error.message); } } async function configure(command) { let adapter = command.parsedFlags.adapter; let ssr = command.parsedFlags.ssr; let shouldInstallPackages = command.parsedFlags.install; let shouldSkipExampleRoute = command.parsedFlags["skip-example-route"]; if (adapter === void 0) { adapter = await command.prompt.choice( "Select the Inertia adapter you want to use", ADAPTERS.map((adapterName) => string.capitalCase(adapterName)), { name: "adapter", result: (value) => value.toLowerCase() } ); } if (ssr === void 0) { ssr = await command.prompt.confirm("Do you want to use server-side rendering?", { name: "ssr" }); } if (adapter in ADAPTERS_INFO === false) { command.logger.error( `The selected adapter "${adapter}" is invalid. Select one from: ${string.sentence( Object.keys(ADAPTERS_INFO) )}` ); command.exitCode = 1; return; } const adapterInfo = ADAPTERS_INFO[adapter]; const codemods = await command.createCodemods(); await codemods.updateRcFile((rcFile) => { rcFile.addProvider("@adonisjs/inertia/inertia_provider"); }); await codemods.registerMiddleware("server", [ { path: "@adonisjs/inertia/inertia_middleware", position: "after" } ]); const appExt = adapterInfo.appExtension; const stubFolder = adapterInfo.stubFolder; const compExt = adapterInfo.componentsExtension; await codemods.makeUsingStub(stubsRoot, "config.stub", { ssr, ssrEntrypoint: adapterInfo.ssrEntrypoint }); await codemods.makeUsingStub(stubsRoot, `app.css.stub`, {}); await codemods.makeUsingStub(stubsRoot, `${stubFolder}/root.edge.stub`, {}); await codemods.makeUsingStub(stubsRoot, `${stubFolder}/tsconfig.json.stub`, {}); await codemods.makeUsingStub(stubsRoot, `${stubFolder}/app.${appExt}.stub`, { ssr }); await codemods.makeUsingStub(stubsRoot, `${stubFolder}/home.${compExt}.stub`, {}); await codemods.makeUsingStub(stubsRoot, `${stubFolder}/errors/not_found.${compExt}.stub`, {}); await codemods.makeUsingStub(stubsRoot, `${stubFolder}/errors/server_error.${compExt}.stub`, {}); if (ssr) { await codemods.makeUsingStub(stubsRoot, `${stubFolder}/ssr.${appExt}.stub`, {}); } const inertiaPluginCall = ssr ? `inertia({ ssr: { enabled: true, entrypoint: 'inertia/app/ssr.${appExt}' } })` : `inertia({ ssr: { enabled: false } })`; await codemods.registerVitePlugin(inertiaPluginCall, [ { isNamed: false, module: "@adonisjs/inertia/client", identifier: "inertia" } ]); await codemods.registerVitePlugin( ssr && adapterInfo.viteRegister.ssrPluginCall ? adapterInfo.viteRegister.ssrPluginCall : adapterInfo.viteRegister.pluginCall, adapterInfo.viteRegister.importDeclarations ); const adonisjsPluginCall = `adonisjs({ entrypoints: ['inertia/app/app.${appExt}'], reload: ['resources/views/**/*.edge'] })`; await codemods.registerVitePlugin(adonisjsPluginCall, [ { isNamed: false, module: "@adonisjs/vite/client", identifier: "adonisjs" } ]); if (shouldSkipExampleRoute !== true) { await defineExampleRoute(command, codemods); } const pkgToInstall = adapterInfo.dependencies; if (ssr && adapterInfo.ssrDependencies) { pkgToInstall.push(...adapterInfo.ssrDependencies); } if (shouldInstallPackages === void 0) { shouldInstallPackages = await command.prompt.confirm( `Do you want to install dependencies ${pkgToInstall.map((pkg) => pkg.name).join(", ")}?`, { name: "install" } ); } if (shouldInstallPackages) { await codemods.installPackages(pkgToInstall); } else { await codemods.listPackagesToInstall(pkgToInstall); } } // src/define_config.ts import { slash } from "@poppinss/utils"; import { configProvider } from "@adonisjs/core"; // src/version_cache.ts import { createHash } from "crypto"; import { readFile } from "fs/promises"; var VersionCache = class { constructor(appRoot, assetsVersion) { this.appRoot = appRoot; this.assetsVersion = assetsVersion; this.#cachedVersion = assetsVersion; } #cachedVersion; /** * Compute the hash of the manifest file and cache it */ async #getManifestHash() { try { const manifestPath = new URL("public/assets/.vite/manifest.json", this.appRoot); const manifestFile = await readFile(manifestPath, "utf-8"); this.#cachedVersion = createHash("md5").update(manifestFile).digest("hex"); return this.#cachedVersion; } catch { this.#cachedVersion = "1"; return this.#cachedVersion; } } /** * Pre-compute the version */ async computeVersion() { if (!this.assetsVersion) await this.#getManifestHash(); return this; } /** * Returns the current assets version */ getVersion() { if (!this.#cachedVersion) throw new Error("Version has not been computed yet"); return this.#cachedVersion; } /** * Set the assets version */ async setVersion(version) { this.#cachedVersion = version; } }; // src/files_detector.ts import { locatePath } from "locate-path"; var FilesDetector = class { constructor(app) { this.app = app; } /** * Try to locate the entrypoint file based * on the conventional locations */ async detectEntrypoint(defaultPath) { const possiblesLocations = [ "./inertia/app/app.ts", "./inertia/app/app.tsx", "./resources/app.ts", "./resources/app.tsx", "./resources/app.jsx", "./resources/app.js", "./inertia/app/app.jsx" ]; const path = await locatePath(possiblesLocations, { cwd: this.app.appRoot }); return this.app.makePath(path || defaultPath); } /** * Try to locate the SSR entrypoint file based * on the conventional locations */ async detectSsrEntrypoint(defaultPath) { const possiblesLocations = [ "./inertia/app/ssr.ts", "./inertia/app/ssr.tsx", "./resources/ssr.ts", "./resources/ssr.tsx", "./resources/ssr.jsx", "./resources/ssr.js", "./inertia/app/ssr.jsx" ]; const path = await locatePath(possiblesLocations, { cwd: this.app.appRoot }); return this.app.makePath(path || defaultPath); } /** * Try to locate the SSR bundle file based * on the conventional locations */ async detectSsrBundle(defaultPath) { const possiblesLocations = ["./ssr/ssr.js", "./ssr/ssr.mjs"]; const path = await locatePath(possiblesLocations, { cwd: this.app.appRoot }); return this.app.makePath(path || defaultPath); } }; // src/define_config.ts function defineConfig(config) { return configProvider.create(async (app) => { const detector = new FilesDetector(app); const versionCache = new VersionCache(app.appRoot, config.assetsVersion); await versionCache.computeVersion(); return { versionCache, rootView: config.rootView ?? "inertia_layout", sharedData: config.sharedData || {}, history: { encrypt: config.history?.encrypt ?? false }, entrypoint: slash( config.entrypoint ?? await detector.detectEntrypoint("inertia/app/app.ts") ), ssr: { enabled: config.ssr?.enabled ?? false, pages: config.ssr?.pages, entrypoint: config.ssr?.entrypoint ?? await detector.detectSsrEntrypoint("inertia/app/ssr.ts"), bundle: config.ssr?.bundle ?? await detector.detectSsrBundle("ssr/ssr.js") } }; }); } export { configure, defineConfig, stubsRoot };