diff --git a/src/Illuminate/Foundation/Console/VueInstallCommand.php b/src/Illuminate/Foundation/Console/VueInstallCommand.php new file mode 100644 index 000000000000..c17188376064 --- /dev/null +++ b/src/Illuminate/Foundation/Console/VueInstallCommand.php @@ -0,0 +1,233 @@ +laravel->path('Http/Middleware/HandleInertiaRequests.php'); + + $inertiaConfigPath = $this->laravel->configPath('inertia.php'); + + if (file_exists($inertiaMiddlewarePath) || file_exists($inertiaConfigPath)) { + $this->components->error('Vue.js scaffolding is already configured.'); + } else { + $this->components->info('Install and configure Vue.js scaffolding.'); + + $this->installInertia(); + + $this->installZiggy(); + + $this->ensureDirectoriesExist([ + $this->laravel->path('Http/Middleware'), + $this->laravel->resourcePath('js/lib'), + $this->laravel->resourcePath('js/pages'), + $this->laravel->resourcePath('js/types'), + ]); + + $this->publishFiles([ + // inertia files + __DIR__.'/stubs/vue-scaffolding/inertia/HandleInertiaRequests.stub' => $inertiaMiddlewarePath, + __DIR__.'/stubs/vue-scaffolding/inertia/inertia.stub' => $inertiaConfigPath, + + // js files + __DIR__.'/stubs/vue-scaffolding/js/lib/utils.stub' => $this->laravel->resourcePath('js/lib/utils.ts'), + __DIR__.'/stubs/vue-scaffolding/js/pages/Welcome.stub' => $this->laravel->resourcePath('js/pages/Welcome.vue'), + __DIR__.'/stubs/vue-scaffolding/js/types/globals.stub' => $this->laravel->resourcePath('js/types/globals.d.ts'), + __DIR__.'/stubs/vue-scaffolding/js/types/index.stub' => $this->laravel->resourcePath('js/types/index.d.ts'), + __DIR__.'/stubs/vue-scaffolding/js/types/ziggy.stub' => $this->laravel->resourcePath('js/types/ziggy.d.ts'), + __DIR__.'/stubs/vue-scaffolding/js/app.stub' => $this->laravel->resourcePath('js/app.ts'), + __DIR__.'/stubs/vue-scaffolding/js/ssr.stub' => $this->laravel->resourcePath('js/ssr.ts'), + + // view files + __DIR__.'/stubs/vue-scaffolding/welcome.stub' => $this->laravel->resourcePath('views/welcome.blade.php'), + + // routes files + __DIR__.'/stubs/vue-scaffolding/web.stub' => $this->laravel->basePath('routes/web.php'), + + // bootstrap files + __DIR__.'/stubs/vue-scaffolding/app.stub' => $this->laravel->basePath('bootstrap/app.php'), + + // other files + __DIR__.'/stubs/vue-scaffolding/package.stub' => $this->laravel->basePath('package.json'), + __DIR__.'/stubs/vue-scaffolding/eslint.config.stub' => $this->laravel->basePath('eslint.config.js'), + __DIR__.'/stubs/vue-scaffolding/tsconfig.stub' => $this->laravel->basePath('tsconfig.json'), + __DIR__.'/stubs/vue-scaffolding/vite.config.stub' => $this->laravel->basePath('vite.config.ts'), + ]); + + $this->deleteFiles([ + $this->laravel->resourcePath('js/app.js'), + $this->laravel->resourcePath('js/bootstrap.js'), + $this->laravel->basePath('vite.config.js'), + ]); + + $this->cleanCssFile(); + + $this->addDevSsrCommand(); + + $this->installNodeDependencies(); + } + } + + /** + * Install Inertia into the application. + * + * @return void + */ + protected function installInertia() + { + $this->components->info('Installing Inertia...'); + + $this->requireComposerPackages($this->option('composer'), [ + 'inertiajs/inertia-laravel:^2.0', + ]); + } + + /** + * Install Ziggy into the application. + * + * @return void + */ + protected function installZiggy() + { + $this->output->newLine(); + $this->components->info('Installing Ziggy...'); + + $this->requireComposerPackages($this->option('composer'), [ + 'tightenco/ziggy:^2.5', + ]); + } + + /** + * Ensure that the given directories exist, creating them if necessary. + * + * @param list $directories + * @return void + */ + protected function ensureDirectoriesExist($directories) + { + foreach ($directories as $directory) { + File::ensureDirectoryExists($directory); + } + } + + /** + * Publish the given files to their destination paths. + * + * @param array $files + * @return void + */ + protected function publishFiles($files) + { + foreach ($files as $source => $destination) { + File::copy($source, $destination); + } + } + + /** + * Delete the given files if they exist. + * + * @param list $files + * @return void + */ + protected function deleteFiles($files) + { + foreach ($files as $file) { + File::delete($file); + } + } + + /** + * Remove some directives from the "app.css" file. + * + * @return void + */ + protected function cleanCssFile() + { + $filePath = $this->laravel->resourcePath('css/app.css'); + + $str = "@source '../**/*.blade.php';\n@source '../**/*.js';\n"; + + if (str_contains(File::get($filePath), $str)) { + File::replaceInFile($str, '', $filePath); + } + } + + /** + * Add the `dev:ssr` command to the "composer.json" file. + * + * @return void + */ + protected function addDevSsrCommand() + { + $file = $this->laravel->basePath('composer.json'); + + $content = json_decode(File::get($file), true); + + $content['scripts'] = Arr::add($content['scripts'], 'dev:ssr', [ + 'npm run build:ssr', + 'Composer\\Config::disableProcessTimeout', + 'npx concurrently -c "#93c5fd,#c4b5fd,#fb7185,#fdba74" "php artisan serve" "php artisan queue:listen --tries=1" "php artisan pail --timeout=0" "php artisan inertia:start-ssr" --names=server,queue,logs,ssr --kill-others', + ]); + + File::put( + $file, + json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)."\n" + ); + } + + /** + * Run the `npm install` command in the base path of the application. + * + * @return void + */ + protected function installNodeDependencies() + { + if (! $this->confirm('Would you like to install the Node dependencies?', default: true)) { + $this->components->warn("Please run the 'npm install' command manually."); + + return; + } + + try { + $command = Process::timeout(120) + ->path($this->laravel->basePath()) + ->run('npm install'); + + $this->components->info('Node dependencies installed successfully.'); + } catch (ProcessTimedOutException $e) { + $this->components->warn("Node dependency installation failed. Please run the 'npm install' command."); + } + } +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/app.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/app.stub new file mode 100644 index 000000000000..bf216c281ab4 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/app.stub @@ -0,0 +1,23 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware): void { + $middleware->web(append: [ + HandleInertiaRequests::class, + AddLinkHeadersForPreloadedAssets::class, + ]); + }) + ->withExceptions(function (Exceptions $exceptions): void { + // + })->create(); diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/eslint.config.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/eslint.config.stub new file mode 100644 index 000000000000..388a5a68f8fb --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/eslint.config.stub @@ -0,0 +1,19 @@ +import prettier from 'eslint-config-prettier'; +import vue from 'eslint-plugin-vue'; + +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'; + +export default defineConfigWithVueTs( + vue.configs['flat/essential'], + vueTsConfigs.recommended, + { + ignores: ['vendor', 'node_modules', 'public', 'bootstrap/ssr', 'tailwind.config.js', 'resources/js/components/ui/*'], + }, + { + rules: { + 'vue/multi-word-component-names': 'off', + '@typescript-eslint/no-explicit-any': 'off', + }, + }, + prettier, +); diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/inertia/HandleInertiaRequests.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/inertia/HandleInertiaRequests.stub new file mode 100644 index 000000000000..204e9280ac79 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/inertia/HandleInertiaRequests.stub @@ -0,0 +1,55 @@ + + */ + public function share(Request $request): array + { + [$message, $author] = str(Inspiring::quotes()->random())->explode('-'); + + return [ + ...parent::share($request), + 'name' => config('app.name'), + 'quote' => ['message' => trim($message), 'author' => trim($author)], + 'auth' => [ + 'user' => $request->user(), + ], + 'ziggy' => [ + ...(new Ziggy)->toArray(), + 'location' => $request->url(), + ], + ]; + } +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/inertia/inertia.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/inertia/inertia.stub new file mode 100644 index 000000000000..d15cad9460d2 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/inertia/inertia.stub @@ -0,0 +1,52 @@ + [ + 'enabled' => true, + 'url' => 'http://127.0.0.1:13714', + // 'bundle' => base_path('bootstrap/ssr/ssr.mjs'), + ], + + /* + |-------------------------------------------------------------------------- + | Testing + |-------------------------------------------------------------------------- + | + | The values described here are used to locate Inertia components on the + | filesystem. For instance, when using `assertInertia`, the assertion + | attempts to locate the component as a file relative to the paths. + | + */ + + 'testing' => [ + 'ensure_pages_exist' => true, + + 'page_paths' => [ + resource_path('js/pages'), + ], + + 'page_extensions' => [ + 'js', + 'jsx', + 'svelte', + 'ts', + 'tsx', + 'vue', + ], + ], + +]; diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/app.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/app.stub new file mode 100644 index 000000000000..01bba54a0c7d --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/app.stub @@ -0,0 +1,23 @@ +import '../css/app.css'; + +import { createInertiaApp } from '@inertiajs/vue3'; +import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; +import type { DefineComponent } from 'vue'; +import { createApp, h } from 'vue'; +import { ZiggyVue } from 'ziggy-js'; + +const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; + +createInertiaApp({ + title: (title) => (title ? `${title} - ${appName}` : appName), + resolve: (name) => resolvePageComponent(`./pages/${name}.vue`, import.meta.glob('./pages/**/*.vue')), + setup({ el, App, props, plugin }) { + createApp({ render: () => h(App, props) }) + .use(plugin) + .use(ZiggyVue) + .mount(el); + }, + progress: { + color: '#4B5563', + }, +}); diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/lib/utils.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/lib/utils.stub new file mode 100644 index 000000000000..3877c89f2364 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/lib/utils.stub @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/pages/Welcome.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/pages/Welcome.stub new file mode 100644 index 000000000000..d9aacd8fe98a --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/pages/Welcome.stub @@ -0,0 +1,761 @@ + + + diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/ssr.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/ssr.stub new file mode 100644 index 000000000000..8fcdebeac7f8 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/ssr.stub @@ -0,0 +1,31 @@ +import { createInertiaApp } from '@inertiajs/vue3'; +import createServer from '@inertiajs/vue3/server'; +import { renderToString } from 'vue/server-renderer'; +import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; +import { createSSRApp, DefineComponent, h } from 'vue'; +import { ZiggyVue } from 'ziggy-js'; + +const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; + +createServer((page) => + createInertiaApp({ + page, + render: renderToString, + title: (title) => title ? `${title} - ${appName}` : appName, + resolve: resolvePage, + setup: ({ App, props, plugin }) => + createSSRApp({ render: () => h(App, props) }) + .use(plugin) + .use(ZiggyVue, { + ...page.props.ziggy, + location: new URL(page.props.ziggy.location), + }), + }), + { cluster: true }, +); + +function resolvePage(name: string) { + const pages = import.meta.glob('./pages/**/*.vue'); + + return resolvePageComponent(`./pages/${name}.vue`, pages); +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/globals.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/globals.stub new file mode 100644 index 000000000000..b08451c491a7 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/globals.stub @@ -0,0 +1,26 @@ +import { AppPageProps } from '@/types/index'; + +// Extend ImportMeta interface for Vite... +declare module 'vite/client' { + interface ImportMetaEnv { + readonly VITE_APP_NAME: string; + [key: string]: string | boolean | undefined; + } + + interface ImportMeta { + readonly env: ImportMetaEnv; + readonly glob: (pattern: string) => Record Promise>; + } +} + +declare module '@inertiajs/core' { + interface PageProps extends InertiaPageProps, AppPageProps {} +} + +declare module 'vue' { + interface ComponentCustomProperties { + $inertia: typeof Router; + $page: Page; + $headManager: ReturnType; + } +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/index.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/index.stub new file mode 100644 index 000000000000..2a160b17f063 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/index.stub @@ -0,0 +1,22 @@ +import type { Config } from 'ziggy-js'; + +export interface Auth { + user: User; +} + +export type AppPageProps = Record> = T & { + name: string; + quote: { message: string; author: string }; + auth: Auth; + ziggy: Config & { location: string }; +}; + +export interface User { + id: number; + name: string; + email: string; + avatar?: string; + email_verified_at: string | null; + created_at: string; + updated_at: string; +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/ziggy.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/ziggy.stub new file mode 100644 index 000000000000..56d8a74bbd9a --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/js/types/ziggy.stub @@ -0,0 +1,11 @@ +import { route } from 'ziggy-js'; + +declare global { + let route: typeof route; +} + +declare module 'vue' { + interface ComponentCustomProperties { + route: typeof route; + } +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/package.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/package.stub new file mode 100644 index 000000000000..28f835b6a8fa --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/package.stub @@ -0,0 +1,47 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "build:ssr": "vite build && vite build --ssr", + "dev": "vite", + "format": "prettier --write resources/", + "format:check": "prettier --check resources/", + "lint": "eslint . --fix" + }, + "devDependencies": { + "@eslint/js": "^9.19.0", + "@types/node": "^22.13.5", + "@vue/eslint-config-typescript": "^14.3.0", + "eslint": "^9.17.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-vue": "^9.32.0", + "prettier": "^3.4.2", + "prettier-plugin-organize-imports": "^4.1.0", + "prettier-plugin-tailwindcss": "^0.6.11", + "typescript-eslint": "^8.23.0", + "vue-tsc": "^2.2.4" + }, + "dependencies": { + "@inertiajs/vue3": "^2.0.0", + "@tailwindcss/vite": "^4.1.11", + "@vitejs/plugin-vue": "^6.0.0", + "@vueuse/core": "^12.8.2", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^2.0.0", + "tailwind-merge": "^3.2.0", + "tailwindcss": "^4.1.1", + "typescript": "^5.2.2", + "vite": "^7.1.2", + "vue": "^3.5.13", + "ziggy-js": "^2.4.2" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "4.9.5", + "@tailwindcss/oxide-linux-x64-gnu": "^4.0.1", + "lightningcss-linux-x64-gnu": "^1.29.1" + } +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/tsconfig.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/tsconfig.stub new file mode 100644 index 000000000000..93d12bcd89ef --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/tsconfig.stub @@ -0,0 +1,126 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "useDefineForClassFields": true, + "lib": [ + "ESNext", + "DOM", + "DOM.Iterable" + ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + "jsx": "preserve" /* Specify what JSX code is generated. */, + "jsxImportSource": "vue" /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */, + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ESNext" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + /* Specify a set of entries that re-map imports to additional lookup locations. */ "@/*": ["./resources/js/*"], + }, + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": [ + "vite/client", + "./resources/js/types" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ + "resolveJsonModule": true /* Enable importing .json files. */, + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + "sourceMap": true /* Create source map files for emitted JavaScript files. */, + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + "noEmit": true /* Disable emitting files from a compilation. */, + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": [ + "resources/js/**/*.ts", + "resources/js/**/*.d.ts", + "resources/js/**/*.tsx", + "resources/js/**/*.vue" + ] +} diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/vite.config.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/vite.config.stub new file mode 100644 index 000000000000..711601dd44d9 --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/vite.config.stub @@ -0,0 +1,23 @@ +import vue from '@vitejs/plugin-vue'; +import laravel from 'laravel-vite-plugin'; +import tailwindcss from '@tailwindcss/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [ + laravel({ + input: ['resources/js/app.ts'], + ssr: 'resources/js/ssr.ts', + refresh: true, + }), + tailwindcss(), + vue({ + template: { + transformAssetUrls: { + base: null, + includeAbsolute: false, + }, + }, + }), + ], +}); diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/web.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/web.stub new file mode 100644 index 000000000000..99ab7deb69ce --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/web.stub @@ -0,0 +1,8 @@ +name('home'); diff --git a/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/welcome.stub b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/welcome.stub new file mode 100644 index 000000000000..4e3dcd5a9d5e --- /dev/null +++ b/src/Illuminate/Foundation/Console/stubs/vue-scaffolding/welcome.stub @@ -0,0 +1,23 @@ + + ($appearance ?? 'system') == 'dark'])> + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + + + @routes + @vite(['resources/js/app.ts', "resources/js/pages/{$page['component']}.vue"]) + @inertiaHead + + + @inertia + + diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index ae5fdc9c9c4e..a54bb32d4823 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -87,6 +87,7 @@ use Illuminate\Foundation\Console\ViewCacheCommand; use Illuminate\Foundation\Console\ViewClearCommand; use Illuminate\Foundation\Console\ViewMakeCommand; +use Illuminate\Foundation\Console\VueInstallCommand; use Illuminate\Notifications\Console\NotificationTableCommand; use Illuminate\Queue\Console\BatchesTableCommand; use Illuminate\Queue\Console\ClearCommand as QueueClearCommand; @@ -226,6 +227,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'TraitMake' => TraitMakeCommand::class, 'VendorPublish' => VendorPublishCommand::class, 'ViewMake' => ViewMakeCommand::class, + 'VueInstall' => VueInstallCommand::class, ]; /**