diff --git a/package-lock.json b/package-lock.json index 7cd866f..df458d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@athenna/http", - "version": "5.9.0", + "version": "5.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@athenna/http", - "version": "5.9.0", + "version": "5.11.0", "license": "MIT", "devDependencies": { "@athenna/artisan": "^5.3.0", diff --git a/package.json b/package.json index d19a130..556fa42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/http", - "version": "5.10.0", + "version": "5.11.0", "description": "The Athenna Http server. Built on top of fastify.", "license": "MIT", "author": "João Lenon ", @@ -51,7 +51,7 @@ "./types": "./src/types/index.js", "./package": "./package.json", "./package.json": "./package.json", - "./vite": "./src/vite/index.js", + "./vite/plugin": "./src/vite/plugin.js", "./testing/plugins": "./src/testing/plugins/index.js", "./kernels/HttpKernel": "./src/kernels/HttpKernel.js", "./handlers/HttpExceptionHandler": "./src/handlers/HttpExceptionHandler.js", diff --git a/src/types/vite/PluginOptions.ts b/src/types/vite/PluginOptions.ts new file mode 100644 index 0000000..cb579ad --- /dev/null +++ b/src/types/vite/PluginOptions.ts @@ -0,0 +1,37 @@ +/** + * @athenna/http + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +export interface PluginOptions { + /** + * The URL where the assets will be served. This is particularly + * useful if you are using a CDN to deploy your assets. + * + * @default '' + */ + assetsUrl?: string + + /** + * Files that should trigger a page reload when changed. + * + * @default ['./src/resources/views/** /*.edge'] + */ + reload?: string[] + + /** + * Paths to the entrypoints files + */ + entrypoints: string[] + + /** + * Public directory where the assets will be compiled. + * + * @default 'public/assets' + */ + buildDirectory?: string +} diff --git a/src/vite/config.ts b/src/vite/config.ts new file mode 100644 index 0000000..71da9c3 --- /dev/null +++ b/src/vite/config.ts @@ -0,0 +1,77 @@ +/** + * @athenna/http + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { join } from 'node:path' +import type { ConfigEnv, Plugin, UserConfig } from 'vite' +import type { PluginOptions } from '#src/types/vite/PluginOptions' + +/** + * Resolve the `config.base` value + */ +export function resolveBase( + config: UserConfig, + options: Required, + command: 'build' | 'serve' +): string { + if (config.base) return config.base + if (command === 'build') { + return options.assetsUrl.endsWith('/') + ? options.assetsUrl + : options.assetsUrl + '/' + } + + return '/' +} + +/** + * Vite config hook + */ +export function configHook( + options: Required, + userConfig: UserConfig, + { command }: ConfigEnv +): UserConfig { + const config: UserConfig = { + publicDir: userConfig.publicDir ?? false, + base: resolveBase(userConfig, options, command), + + /** + * Disable the vite dev server cors handling. Otherwise, it will + * override the cors settings defined by @fastify/cors. + */ + server: { cors: userConfig.server?.cors ?? false }, + + build: { + assetsDir: '', + emptyOutDir: true, + manifest: userConfig.build?.manifest ?? true, + outDir: userConfig.build?.outDir ?? options.buildDirectory, + assetsInlineLimit: userConfig.build?.assetsInlineLimit ?? 0, + + rollupOptions: { + input: options.entrypoints.map(entrypoint => + join(userConfig.root || '', entrypoint) + ) + } + } + } + + return config +} + +/** + * Update the user vite config to match Athenna requirements. + */ +export const config = (options: Required): Plugin => { + return { + name: 'vite-plugin-athenna:config', + enforce: 'post', + config: configHook.bind(null, options) + } +} diff --git a/src/vite/index.ts b/src/vite/index.ts deleted file mode 100644 index 2e8b4cc..0000000 --- a/src/vite/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import PluginRestart from 'vite-plugin-restart' - -import { Path } from '@athenna/common' -import { mergeConfig, defineConfig, type UserConfig } from 'vite' - -export function defineAthennaConfig(config: UserConfig) { - const defaultConfig = { - root: Path.pwd(), - assetsUrl: '/assets', - buildDirectory: 'public/assets', - css: { - preprocessorOptions: { - scss: { - api: 'modern' - } - } - }, - build: { - assetsDir: '', - manifest: true, - emptyOutDir: true, - outDir: 'public/assets', - assetsInlineLimit: 0, - rollupOptions: { - output: { - entryFileNames: '[name].js', - chunkFileNames: '[name].js', - assetFileNames: '[name].[ext]' - }, - input: [Path.resources('css/app.scss'), Path.resources('js/app.js')] - } - }, - plugins: [PluginRestart({ reload: [Path.views('**/*.edge')] })] - } - - return defineConfig(mergeConfig(defaultConfig, config)) -} diff --git a/src/vite/plugin.ts b/src/vite/plugin.ts new file mode 100644 index 0000000..44f09d2 --- /dev/null +++ b/src/vite/plugin.ts @@ -0,0 +1,34 @@ +/** + * @athenna/http + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import PluginRestart from 'vite-plugin-restart' + +import { config } from '#src/vite/config' +import type { PluginOption } from 'vite' +import type { PluginOptions } from '#src/types/vite/PluginOptions' + +export default function athenna(options: PluginOptions): PluginOption[] { + const fullOptions = Object.assign( + { + assetsUrl: '/assets', + buildDirectory: 'public/assets', + reload: ['./src/resources/views/**/*.edge'], + css: { + preprocessorOptions: { + scss: { + api: 'modern' + } + } + } + }, + options + ) + + return [PluginRestart({ reload: fullOptions.reload }), config(fullOptions)] +}