diff --git a/.env.example.json b/.env.example.json
index 24fdd44..7c7aef7 100644
--- a/.env.example.json
+++ b/.env.example.json
@@ -56,5 +56,10 @@
"SMTP_TIMEOUT": 50,
"MAIL_FROM_EMAIL": "example@domain.com",
- "MAIL_FROM_NAME": "Bow Framework"
+ "MAIL_FROM_NAME": "Bow Framework",
+
+ "VITE_APP_NAME": "Bow Application",
+ "VITE_APP_URL": "http://localhost:5000",
+ "VITE_API_URL": "http://localhost:5000/api",
+ "VITE_APP_DEBUG": true
}
diff --git a/app/Kernel.php b/app/Kernel.php
index 7a395cd..70c8232 100644
--- a/app/Kernel.php
+++ b/app/Kernel.php
@@ -3,6 +3,7 @@
namespace App;
use Bow\Router\Router;
+use Bow\Scheduler\Scheduler;
use Bow\Configuration\Loader as ApplicationLoader;
class Kernel extends ApplicationLoader
@@ -20,6 +21,19 @@ public function events(): array
];
}
+ /**
+ * Define your scheduled tasks
+ *
+ * @param Scheduler $schedule
+ * @return void
+ */
+ public function schedules(Scheduler $schedule): void
+ {
+ // Define your scheduled tasks here
+ // $schedule->command("cache:clear")->daily();
+ // $schedule->call(fn () => logger()->info("Heartbeat"))->everyMinute();
+ }
+
/**
* Define the app namespace
*
diff --git a/public/img/logo.png b/public/img/logo.png
deleted file mode 100644
index dd384b5..0000000
Binary files a/public/img/logo.png and /dev/null differ
diff --git a/public/img/logo.svg b/public/img/logo.svg
new file mode 100644
index 0000000..2b03a43
--- /dev/null
+++ b/public/img/logo.svg
@@ -0,0 +1,38 @@
+
diff --git a/seeders/20251220174703-user-seeder.php b/seeders/20251220174703-user-seeder.php
index 5d403c6..1b4e185 100644
--- a/seeders/20251220174703-user-seeder.php
+++ b/seeders/20251220174703-user-seeder.php
@@ -10,16 +10,16 @@ public function run()
$faker = FakerFactory::create();
foreach (range(1, 5) as $value) {
- $user = [
+ $user = User::create([
'name' => $faker->name,
'description' => $faker->text(100),
'email' => $faker->email,
'password' => app_hash('password'),
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
- ];
+ ]);
- User::create($user);
+ $user->persist();
}
}
}
diff --git a/templates/layouts/default.tintin.php b/templates/layouts/default.tintin.php
index 941c8f6..ed099b6 100644
--- a/templates/layouts/default.tintin.php
+++ b/templates/layouts/default.tintin.php
@@ -1,107 +1,54 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ Construisez avec Bow
+ Un framework PHP léger et expressif conçu pour les développeurs qui valorisent la simplicité et la productivité.
+
+
+
+
+
+
+
Rapide
+
Architecture légère optimisée pour des performances maximales.
+
+
+
+
Simple
+
API intuitive et documentation complète pour démarrer rapidement.
+
+
+
+
Flexible
+
Modulaire et extensible selon les besoins de votre projet.
+
+
+
+
+ Commencez en quelques lignes
+ Définissez vos routes simplement
+
+
$router->get('/', fn() => view('welcome'));
$router->get('/users/:id', [UserController::class, 'show']);
+
+
+
+
+
%endblock
diff --git a/vite.config.js b/vite.config.js
index f11bb77..bcda1b2 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,63 +1,150 @@
-import { defineConfig } from 'vite';
+import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import react from '@vitejs/plugin-react';
-import path from 'path';
import tailwindcss from '@tailwindcss/vite';
+import { resolve } from 'path';
+import { existsSync, readFileSync } from 'fs';
-export default defineConfig({
- plugins: [
- vue(),
- react(),
- tailwindcss(),
- ],
- root: path.resolve(__dirname, 'assets'),
- build: {
- outDir: path.resolve(__dirname, 'public'),
- emptyOutDir: true,
- rollupOptions: {
- input: {
- app: path.resolve(__dirname, 'assets/js/app.js'),
- },
- output: {
- entryFileNames: 'js/[name].js',
- chunkFileNames: 'js/[name]-[hash].js',
- assetFileNames: (assetInfo) => {
- // Place images/fonts in their own folders, css in css/
- const ext = assetInfo.name.split('.').pop();
- if (/\.(css|scss|sass|less)$/.test(assetInfo.name)) {
- return 'css/[name]-[hash][extname]';
- }
- if (/\.(png|jpe?g|gif|svg|webp|ico)$/.test(assetInfo.name)) {
- return 'img/[name]-[hash][extname]';
- }
- if (/\.(woff2?|eot|ttf|otf)$/.test(assetInfo.name)) {
- return 'fonts/[name]-[hash][extname]';
- }
- return '[ext]/[name]-[hash][extname]';
- },
- },
- },
- },
- css: {
- preprocessorOptions: {
- scss: {
- additionalData: `@import "${path.resolve(__dirname, 'assets/sass/variables.scss')}";`,
- },
- less: {
- javascriptEnabled: true,
- },
- },
- },
- resolve: {
- alias: {
- '@': path.resolve(__dirname, 'assets/js'),
- '@sass': path.resolve(__dirname, 'assets/sass'),
- },
- },
- server: {
- watch: {
- usePolling: true,
- },
- },
+// Load .env.json if exists
+const loadBowEnv = () => {
+ const envPath = resolve(__dirname, '.env.json');
+ if (existsSync(envPath)) {
+ try {
+ const env = JSON.parse(readFileSync(envPath, 'utf-8'));
+ // Expose VITE_* variables
+ Object.keys(env).forEach((key) => {
+ if (key.startsWith('VITE_')) {
+ process.env[key] = env[key];
+ }
+ });
+ return env;
+ } catch (e) {
+ console.warn('Failed to parse .env.json:', e.message);
+ }
+ }
+ return {};
+};
+
+export default defineConfig(({ mode }) => {
+ const bowEnv = loadBowEnv();
+ const isDev = mode === 'development';
+ const isProd = mode === 'production';
+
+ return {
+ plugins: [
+ vue({
+ script: {
+ defineModel: true,
+ propsDestructure: true,
+ },
+ }),
+ react({
+ fastRefresh: true,
+ }),
+ tailwindcss(),
+ ],
+
+ root: resolve(__dirname, 'assets'),
+ publicDir: resolve(__dirname, 'public/static'),
+
+ build: {
+ outDir: resolve(__dirname, 'public'),
+ emptyOutDir: false,
+ manifest: isProd,
+ sourcemap: isDev,
+ minify: isProd ? 'esbuild' : false,
+ target: 'es2020',
+ cssCodeSplit: true,
+ chunkSizeWarningLimit: 500,
+
+ rollupOptions: {
+ input: {
+ app: resolve(__dirname, 'assets/js/app.js'),
+ },
+ output: {
+ entryFileNames: isProd ? 'js/[name]-[hash].js' : 'js/[name].js',
+ chunkFileNames: 'js/chunks/[name]-[hash].js',
+ assetFileNames: (assetInfo) => {
+ const name = assetInfo.name || '';
+ if (/\.(css|scss|sass|less)$/.test(name)) {
+ return isProd ? 'css/[name]-[hash][extname]' : 'css/[name][extname]';
+ }
+ if (/\.(png|jpe?g|gif|svg|webp|ico|avif)$/.test(name)) {
+ return 'img/[name]-[hash][extname]';
+ }
+ if (/\.(woff2?|eot|ttf|otf)$/.test(name)) {
+ return 'fonts/[name]-[hash][extname]';
+ }
+ if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)$/.test(name)) {
+ return 'media/[name]-[hash][extname]';
+ }
+ return 'assets/[name]-[hash][extname]';
+ },
+ manualChunks: isProd
+ ? {
+ vendor: ['vue', 'react', 'react-dom'],
+ }
+ : undefined,
+ },
+ },
+ },
+
+ css: {
+ devSourcemap: true,
+ preprocessorOptions: {
+ scss: {
+ additionalData: `@use "${resolve(__dirname, 'assets/sass/variables.scss')}" as *;`,
+ silenceDeprecations: ['legacy-js-api'],
+ },
+ },
+ },
+
+ resolve: {
+ alias: {
+ '@': resolve(__dirname, 'assets/js'),
+ '@components': resolve(__dirname, 'assets/js/components'),
+ '@sass': resolve(__dirname, 'assets/sass'),
+ '@css': resolve(__dirname, 'assets/css'),
+ '@img': resolve(__dirname, 'assets/img'),
+ },
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue', '.json'],
+ },
+
+ server: {
+ host: '0.0.0.0',
+ port: 5173,
+ strictPort: false,
+ open: false,
+ cors: true,
+ hmr: {
+ overlay: true,
+ },
+ watch: {
+ usePolling: true,
+ interval: 100,
+ },
+ },
+
+ preview: {
+ host: '0.0.0.0',
+ port: 4173,
+ open: false,
+ },
+
+ optimizeDeps: {
+ include: ['vue', 'react', 'react-dom'],
+ exclude: [],
+ },
+
+ esbuild: {
+ drop: isProd ? ['console', 'debugger'] : [],
+ legalComments: 'none',
+ },
+
+ define: {
+ __APP_VERSION__: JSON.stringify(process.env.npm_package_version || '1.0.0'),
+ __DEV__: isDev,
+ },
+ };
});