Skip to content

资源打包 (Vite)

简介

Vite 是一个现代前端构建工具,提供极其快速的开发环境,并将你的代码打包用于生产环境。使用 Laravel 构建应用时,你通常会使用 Vite 将应用的 CSS 和 JavaScript 文件打包为生产就绪的资源。

Laravel 通过提供官方插件和 Blade 指令与 Vite 无缝集成,以便在开发和生产环境中加载你的资源。

安装与设置

NOTE

以下文档讨论了如何手动安装和配置 Laravel Vite 插件。然而,Laravel 的入门套件已经包含了所有这些脚手架,是开始使用 Laravel 和 Vite 的最快方式。

安装 Node

在运行 Vite 和 Laravel 插件之前,你必须确保已安装 Node.js (16+) 和 NPM:

shell
node -v
npm -v

你可以从官方 Node 网站使用简单的图形安装程序轻松安装最新版本的 Node 和 NPM。或者,如果你使用 Laravel Sail,你可以通过 Sail 调用 Node 和 NPM:

shell
./vendor/bin/sail node -v
./vendor/bin/sail npm -v

安装 Vite 和 Laravel 插件

在全新安装的 Laravel 中,你会在应用目录结构的根目录中找到一个 package.json 文件。默认的 package.json 文件已经包含了你开始使用 Vite 和 Laravel 插件所需的一切。你可以通过 NPM 安装应用的前端依赖:

shell
npm install

配置 Vite

Vite 通过项目根目录中的 vite.config.js 文件进行配置。你可以根据需要自由自定义此文件,还可以安装你应用需要的任何其他插件,例如 @vitejs/plugin-react@sveltejs/vite-plugin-svelte@vitejs/plugin-vue

Laravel Vite 插件要求你指定应用的入口点。这些可以是 JavaScript 或 CSS 文件,包括预处理语言如 TypeScript、JSX、TSX 和 Sass。

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ],
});

如果你正在构建 SPA,包括使用 Inertia 构建的应用,Vite 在没有 CSS 入口点时效果最佳:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css', // [tl! remove]
            'resources/js/app.js',
        ]),
    ],
});

相反,你应该通过 JavaScript 导入 CSS。通常,这会在应用的 resources/js/app.js 文件中完成:

js
import './bootstrap';
import '../css/app.css'; // [tl! add]

Laravel 插件还支持多个入口点和高级配置选项,例如 SSR 入口点

使用安全开发服务器

如果你的本地开发 Web 服务器通过 HTTPS 提供应用服务,你可能会遇到连接 Vite 开发服务器的问题。

如果你使用 Laravel Herd 并已保护站点安全,或者你使用 Laravel Valet 并已对应用运行了 secure 命令,Laravel Vite 插件将自动检测并使用为你生成的 TLS 证书。

如果你使用的主机名与应用的目录名不匹配来保护站点,你可以在应用的 vite.config.js 文件中手动指定主机:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            // ...
            detectTls: 'my-app.test', // [tl! add]
        }),
    ],
});

使用其他 Web 服务器时,你应该生成一个受信任的证书并手动配置 Vite 使用生成的证书:

js
// ...
import fs from 'fs'; // [tl! add]

const host = 'my-app.test'; // [tl! add]

export default defineConfig({
    // ...
    server: { // [tl! add]
        host, // [tl! add]
        hmr: { host }, // [tl! add]
        https: { // [tl! add]
            key: fs.readFileSync(`/path/to/${host}.key`), // [tl! add]
            cert: fs.readFileSync(`/path/to/${host}.crt`), // [tl! add]
        }, // [tl! add]
    }, // [tl! add]
});

如果你无法为你的系统生成受信任的证书,可以安装和配置 @vitejs/plugin-basic-ssl 插件。使用不受信任的证书时,你需要在运行 npm run dev 命令时,通过控制台中的 "Local" 链接在浏览器中接受 Vite 开发服务器的证书警告。

在 WSL2 上的 Sail 中运行开发服务器

在 Windows Subsystem for Linux 2 (WSL2) 上的 Laravel Sail 中运行 Vite 开发服务器时,你应该将以下配置添加到 vite.config.js 文件中,以确保浏览器可以与开发服务器通信:

js
// ...

export default defineConfig({
    // ...
    server: { // [tl! add:start]
        hmr: {
            host: 'localhost',
        },
    }, // [tl! add:end]
});

如果在开发服务器运行时文件更改未在浏览器中反映,你可能还需要配置 Vite 的 server.watch.usePolling 选项

加载脚本和样式

配置好 Vite 入口点后,你现在可以在添加到应用根模板 <head> 中的 @vite() Blade 指令中引用它们:

blade
<!DOCTYPE html>
<head>
    {{-- ... --}}

    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>

如果你通过 JavaScript 导入 CSS,你只需要包含 JavaScript 入口点:

blade
<!DOCTYPE html>
<head>
    {{-- ... --}}

    @vite('resources/js/app.js')
</head>

@vite 指令将自动检测 Vite 开发服务器并注入 Vite 客户端以启用热模块替换。在构建模式下,该指令将加载你编译和版本化的资源,包括任何导入的 CSS。

如果需要,你还可以在调用 @vite 指令时指定编译资源的构建路径:

blade
<!doctype html>
<head>
    {{-- 给定的构建路径相对于 public 路径。 --}}

    @vite('resources/js/app.js', 'vendor/courier/build')
</head>

内联资源

有时可能需要包含资源的原始内容,而不是链接到资源的版本化 URL。例如,当将 HTML 内容传递给 PDF 生成器时,你可能需要将资源内容直接包含到页面中。你可以使用 Vite facade 提供的 content 方法输出 Vite 资源的内容:

blade
@use('Illuminate\Support\Facades\Vite')

<!doctype html>
<head>
    {{-- ... --}}

    <style>
        {!! Vite::content('resources/css/app.css') !!}
    </style>
    <script>
        {!! Vite::content('resources/js/app.js') !!}
    </script>
</head>

运行 Vite

有两种方式可以运行 Vite。你可以通过 dev 命令运行开发服务器,这在本地开发时很有用。开发服务器将自动检测文件更改并立即在所有打开的浏览器窗口中反映它们。

或者,运行 build 命令将版本化和打包你应用的资源,并准备好部署到生产环境:

shell
# 运行 Vite 开发服务器...
npm run dev

# 为生产环境构建和版本化资源...
npm run build

如果你在 WSL2 上的 Sail 中运行开发服务器,可能需要一些额外的配置选项。

使用 JavaScript

别名

默认情况下,Laravel 插件提供一个常用别名,帮助你快速上手并方便地导入应用的资源:

js
{
    '@' => '/resources/js'
}

你可以通过在 vite.config.js 配置文件中添加你自己的别名来覆盖 '@' 别名:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel(['resources/ts/app.tsx']),
    ],
    resolve: {
        alias: {
            '@': '/resources/ts',
        },
    },
});

Vue

如果你想使用 Vue 框架构建前端,那么你还需要安装 @vitejs/plugin-vue 插件:

shell
npm install --save-dev @vitejs/plugin-vue

然后你可以在 vite.config.js 配置文件中包含该插件。在 Laravel 中使用 Vue 插件时,还需要一些额外的选项:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [
        laravel(['resources/js/app.js']),
        vue({
            template: {
                transformAssetUrls: {
                    // Vue 插件会重写单文件组件中引用的资源 URL,
                    // 使其指向 Laravel Web 服务器。将此设置为 `null`
                    // 允许 Laravel 插件将资源 URL 重写为指向 Vite
                    // 服务器。
                    base: null,

                    // Vue 插件会解析绝对 URL 并将其视为磁盘上
                    // 文件的绝对路径。将此设置为 `false` 将保留
                    // 绝对 URL 不变,以便它们可以按预期引用
                    // public 目录中的资源。
                    includeAbsolute: false,
                },
            },
        }),
    ],
});

NOTE

Laravel 的入门套件已经包含了正确的 Laravel、Vue 和 Vite 配置。这些入门套件提供了开始使用 Laravel、Vue 和 Vite 的最快方式。

React

如果你想使用 React 框架构建前端,那么你还需要安装 @vitejs/plugin-react 插件:

shell
npm install --save-dev @vitejs/plugin-react

然后你可以在 vite.config.js 配置文件中包含该插件:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [
        laravel(['resources/js/app.jsx']),
        react(),
    ],
});

你需要确保任何包含 JSX 的文件都有 .jsx.tsx 扩展名,如果需要,记得更新你的入口点,如上面所示

你还需要在现有的 @vite 指令旁边包含额外的 @viteReactRefresh Blade 指令。

blade
@viteReactRefresh
@vite('resources/js/app.jsx')

@viteReactRefresh 指令必须在 @vite 指令之前调用。

NOTE

Laravel 的入门套件已经包含了正确的 Laravel、React 和 Vite 配置。这些入门套件提供了开始使用 Laravel、React 和 Vite 的最快方式。

Svelte

如果你想使用 Svelte 框架构建前端,那么你还需要安装 @sveltejs/vite-plugin-svelte 插件:

shell
npm install --save-dev @sveltejs/vite-plugin-svelte

然后你可以在 vite.config.js 配置文件中包含该插件。

js
import { svelte } from '@sveltejs/vite-plugin-svelte';
import laravel from 'laravel-vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    laravel({
      input: ['resources/js/app.ts'],
      ssr: 'resources/js/ssr.ts',
      refresh: true,
    }),
    svelte(),
  ],
});

NOTE

Laravel 的入门套件已经包含了正确的 Laravel、Svelte 和 Vite 配置。这些入门套件提供了开始使用 Laravel、Svelte 和 Vite 的最快方式。

Inertia

Laravel Vite 插件提供了一个便捷的 resolvePageComponent 函数来帮助你解析 Inertia 页面组件。以下是在 Vue 3 中使用该辅助函数的示例;不过,你也可以在其他框架(如 React 或 Svelte)中使用该函数:

js
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';

createInertiaApp({
  resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
});

如果你在 Inertia 中使用 Vite 的代码分割功能,我们建议配置资源预取

NOTE

Laravel 的入门套件已经包含了正确的 Laravel、Inertia 和 Vite 配置。这些入门套件提供了开始使用 Laravel、Inertia 和 Vite 的最快方式。

URL 处理

使用 Vite 并在应用的 HTML、CSS 或 JS 中引用资源时,有几个注意事项需要考虑。首先,如果你使用绝对路径引用资源,Vite 将不会在构建中包含该资源;因此,你应该确保该资源在你的 public 目录中可用。使用专用 CSS 入口点时,应避免使用绝对路径,因为在开发期间,浏览器会尝试从托管 CSS 的 Vite 开发服务器加载这些路径,而不是从你的 public 目录加载。

引用相对资源路径时,你应该记住路径是相对于它们被引用的文件的。通过相对路径引用的任何资源都将被 Vite 重写、版本化和打包。

请考虑以下项目结构:

text
public/
  taylor.png
resources/
  js/
    Pages/
      Welcome.vue
  images/
    abigail.png

以下示例演示了 Vite 如何处理相对和绝对 URL:

html
<!-- 此资源不由 Vite 处理,不会包含在构建中 -->
<img src="/taylor.png">

<!-- 此资源将被 Vite 重写、版本化和打包 -->
<img src="../../images/abigail.png">

使用样式表

NOTE

Laravel 的入门套件已经包含了正确的 Tailwind 和 Vite 配置。或者,如果你想在不使用我们入门套件的情况下使用 Tailwind 和 Laravel,请查看 Tailwind 的 Laravel 安装指南

所有 Laravel 应用已经包含 Tailwind 和正确配置的 vite.config.js 文件。因此,你只需要启动 Vite 开发服务器或运行 dev Composer 命令,该命令将同时启动 Laravel 和 Vite 开发服务器:

shell
composer run dev

你应用的 CSS 可以放在 resources/css/app.css 文件中。

使用 Blade 和路由

使用 Vite 处理静态资源

在 JavaScript 或 CSS 中引用资源时,Vite 会自动处理和版本化它们。此外,在构建基于 Blade 的应用时,Vite 还可以处理和版本化你仅在 Blade 模板中引用的静态资源。

然而,为了实现这一点,你需要通过在应用的入口点中导入静态资源来让 Vite 感知你的资源。例如,如果你想处理和版本化存储在 resources/images 中的所有图片和存储在 resources/fonts 中的所有字体,你应该在应用的 resources/js/app.js 入口点中添加以下内容:

js
import.meta.glob([
  '../images/**',
  '../fonts/**',
]);

这些资源现在将在运行 npm run build 时被 Vite 处理。然后你可以在 Blade 模板中使用 Vite::asset 方法引用这些资源,该方法将返回给定资源的版本化 URL:

blade
<img src="{{ Vite::asset('resources/images/logo.png') }}">

保存时刷新

当你的应用使用 Blade 进行传统的服务器端渲染构建时,Vite 可以通过在你对应用中的视图文件进行更改时自动刷新浏览器来改善你的开发工作流程。要开始,你可以简单地将 refresh 选项指定为 true

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            // ...
            refresh: true,
        }),
    ],
});

refresh 选项为 true 时,在运行 npm run dev 期间保存以下目录中的文件将触发浏览器执行全页刷新:

  • app/Livewire/**
  • app/View/Components/**
  • lang/**
  • resources/lang/**
  • resources/views/**
  • routes/**

如果你正在使用 Ziggy 在应用的前端中生成路由链接,监视 routes/** 目录会很有用。

如果这些默认路径不满足你的需求,你可以指定自己的监视路径列表:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            // ...
            refresh: ['resources/views/**'],
        }),
    ],
});

在底层,Laravel Vite 插件使用 vite-plugin-full-reload 包,该包提供了一些高级配置选项来微调此功能的行为。如果你需要这种级别的自定义,可以提供一个 config 定义:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            // ...
            refresh: [{
                paths: ['path/to/watch/**'],
                config: { delay: 300 }
            }],
        }),
    ],
});

别名

在 JavaScript 应用中创建别名来引用经常使用的目录是很常见的。但是,你也可以通过使用 Illuminate\Support\Facades\Vite 类的 macro 方法创建在 Blade 中使用的别名。通常,"macros" 应该在服务提供者boot 方法中定义:

php
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Vite::macro('image', fn (string $asset) => $this->asset("resources/images/{$asset}"));
}

定义 macro 后,可以在模板中调用它。例如,我们可以使用上面定义的 image macro 来引用位于 resources/images/logo.png 的资源:

blade
<img src="{{ Vite::image('logo.png') }}" alt="Laravel Logo">

资源预取

使用 Vite 的代码分割功能构建 SPA 时,所需资源会在每次页面导航时获取。这种行为可能导致 UI 渲染延迟。如果这对你选择的前端框架来说是个问题,Laravel 提供了在初始页面加载时预取应用的 JavaScript 和 CSS 资源的能力。

你可以通过在服务提供者boot 方法中调用 Vite::prefetch 方法来指示 Laravel 预取你的资源:

php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Vite;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        // ...
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Vite::prefetch(concurrency: 3);
    }
}

在上面的示例中,每次页面加载时资源将以最多 3 个并发下载的方式预取。你可以修改并发数以适应应用的需求,或者如果应用应该一次下载所有资源,则不指定并发限制:

php
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Vite::prefetch();
}

默认情况下,预取将在页面 load 事件触发时开始。如果你想自定义预取开始的时间,可以指定 Vite 将监听的事件:

php
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Vite::prefetch(event: 'vite:prefetch');
}

根据上面的代码,当你在 window 对象上手动分发 vite:prefetch 事件时,预取将开始。例如,你可以让预取在页面加载三秒后开始:

html
<script>
    addEventListener('load', () => setTimeout(() => {
        dispatchEvent(new Event('vite:prefetch'))
    }, 3000))
</script>

自定义基础 URL

如果你的 Vite 编译资源部署到与应用分开的域(例如通过 CDN),你必须在应用的 .env 文件中指定 ASSET_URL 环境变量:

ini
ASSET_URL=https://cdn.example.com

配置资源 URL 后,所有重写的资源 URL 将以配置的值为前缀:

text
https://cdn.example.com/build/assets/app.9dce8d17.js

请记住,绝对 URL 不会被 Vite 重写,因此不会加上前缀。

环境变量

你可以通过在应用的 .env 文件中以 VITE_ 前缀来将环境变量注入到 JavaScript 中:

ini
VITE_SENTRY_DSN_PUBLIC=http://example.com

你可以通过 import.meta.env 对象访问注入的环境变量:

js
import.meta.env.VITE_SENTRY_DSN_PUBLIC

在测试中禁用 Vite

Laravel 的 Vite 集成将在运行测试时尝试解析你的资源,这要求你要么运行 Vite 开发服务器,要么构建你的资源。

如果你希望在测试期间 mock Vite,你可以调用 withoutVite 方法,该方法适用于任何扩展了 Laravel TestCase 类的测试:

php
test('without vite example', function () {
    $this->withoutVite();

    // ...
});
php
use Tests\TestCase;

class ExampleTest extends TestCase
{
    public function test_without_vite_example(): void
    {
        $this->withoutVite();

        // ...
    }
}

如果你想为所有测试禁用 Vite,可以在基础 TestCase 类的 setUp 方法中调用 withoutVite 方法:

php
<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    protected function setUp(): void// [tl! add:start]
    {
        parent::setUp();

        $this->withoutVite();
    }// [tl! add:end]
}

服务器端渲染 (SSR)

Laravel Vite 插件使使用 Vite 设置服务器端渲染变得轻松。首先,在 resources/js/ssr.js 创建一个 SSR 入口点,并通过向 Laravel 插件传递配置选项来指定入口点:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            ssr: 'resources/js/ssr.js',
        }),
    ],
});

为确保你不会忘记重建 SSR 入口点,我们建议在应用的 package.json 中增强 "build" 脚本来创建 SSR 构建:

json
"scripts": {
     "dev": "vite",
     "build": "vite build" // [tl! remove]
     "build": "vite build && vite build --ssr" // [tl! add]
}

然后,要构建和启动 SSR 服务器,你可以运行以下命令:

shell
npm run build
node bootstrap/ssr/ssr.js

如果你在使用 Inertia 的 SSR,你可以改用 inertia:start-ssr Artisan 命令来启动 SSR 服务器:

shell
php artisan inertia:start-ssr

NOTE

Laravel 的入门套件已经包含了正确的 Laravel、Inertia SSR 和 Vite 配置。这些入门套件提供了开始使用 Laravel、Inertia SSR 和 Vite 的最快方式。

脚本和样式标签属性

内容安全策略 (CSP) Nonce

如果你希望在脚本和样式标签上包含 nonce 属性作为内容安全策略的一部分,你可以在自定义 middleware 中使用 useCspNonce 方法生成或指定 nonce:

php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Vite;
use Symfony\Component\HttpFoundation\Response;

class AddContentSecurityPolicyHeaders
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        Vite::useCspNonce();

        return $next($request)->withHeaders([
            'Content-Security-Policy' => "script-src 'nonce-".Vite::cspNonce()."'",
        ]);
    }
}

调用 useCspNonce 方法后,Laravel 将自动在所有生成的脚本和样式标签上包含 nonce 属性。

如果你需要在其他地方指定 nonce,包括 Laravel 入门套件中包含的 Ziggy @route 指令,你可以使用 cspNonce 方法检索它:

blade
@routes(nonce: Vite::cspNonce())

如果你已经有一个想让 Laravel 使用的 nonce,可以将该 nonce 传递给 useCspNonce 方法:

php
Vite::useCspNonce($nonce);

子资源完整性 (SRI)

如果你的 Vite manifest 为资源包含 integrity 哈希,Laravel 将自动在它生成的任何脚本和样式标签上添加 integrity 属性,以强制执行子资源完整性。默认情况下,Vite 不在其 manifest 中包含 integrity 哈希,但你可以通过安装 vite-plugin-manifest-sri NPM 插件来启用它:

shell
npm install --save-dev vite-plugin-manifest-sri

然后你可以在 vite.config.js 文件中启用此插件:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import manifestSRI from 'vite-plugin-manifest-sri';// [tl! add]

export default defineConfig({
    plugins: [
        laravel({
            // ...
        }),
        manifestSRI(),// [tl! add]
    ],
});

如果需要,你还可以自定义可以找到完整性哈希的 manifest 键:

php
use Illuminate\Support\Facades\Vite;

Vite::useIntegrityKey('custom-integrity-key');

如果你想完全禁用此自动检测,可以将 false 传递给 useIntegrityKey 方法:

php
Vite::useIntegrityKey(false);

任意属性

如果你需要在脚本和样式标签上包含其他属性,例如 data-turbo-track 属性,你可以通过 useScriptTagAttributesuseStyleTagAttributes 方法指定它们。通常,这些方法应该从服务提供者中调用:

php
use Illuminate\Support\Facades\Vite;

Vite::useScriptTagAttributes([
    'data-turbo-track' => 'reload', // 为属性指定一个值...
    'async' => true, // 指定没有值的属性...
    'integrity' => false, // 排除原本会包含的属性...
]);

Vite::useStyleTagAttributes([
    'data-turbo-track' => 'reload',
]);

如果你需要有条件地添加属性,可以传递一个回调,该回调将接收资源源路径、其 URL、其 manifest 块和整个 manifest:

php
use Illuminate\Support\Facades\Vite;

Vite::useScriptTagAttributes(fn (string $src, string $url, array|null $chunk, array|null $manifest) => [
    'data-turbo-track' => $src === 'resources/js/app.js' ? 'reload' : false,
]);

Vite::useStyleTagAttributes(fn (string $src, string $url, array|null $chunk, array|null $manifest) => [
    'data-turbo-track' => $chunk && $chunk['isEntry'] ? 'reload' : false,
]);

WARNING

当 Vite 开发服务器正在运行时,$chunk$manifest 参数将为 null

高级自定义

开箱即用,Laravel 的 Vite 插件使用合理的约定,应该适用于大多数应用;然而,有时你可能需要自定义 Vite 的行为。为了启用额外的自定义选项,我们提供了以下方法和选项,可以用来代替 @vite Blade 指令:

blade
<!doctype html>
<head>
    {{-- ... --}}

    {{
        Vite::useHotFile(storage_path('vite.hot')) // 自定义 "hot" 文件...
            ->useBuildDirectory('bundle') // 自定义构建目录...
            ->useManifestFilename('assets.json') // 自定义 manifest 文件名...
            ->withEntryPoints(['resources/js/app.js']) // 指定入口点...
            ->createAssetPathsUsing(function (string $path, ?bool $secure) { // 自定义构建资源的后端路径生成...
                return "https://cdn.example.com/{$path}";
            })
    }}
</head>

vite.config.js 文件中,你应该指定相同的配置:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            hotFile: 'storage/vite.hot', // 自定义 "hot" 文件...
            buildDirectory: 'bundle', // 自定义构建目录...
            input: ['resources/js/app.js'], // 指定入口点...
        }),
    ],
    build: {
      manifest: 'assets.json', // 自定义 manifest 文件名...
    },
});

开发服务器跨域资源共享 (CORS)

如果你在从 Vite 开发服务器获取资源时在浏览器中遇到跨域资源共享 (CORS) 问题,你可能需要授予你的自定义来源对开发服务器的访问权限。Vite 与 Laravel 插件结合使用时,无需任何额外配置即可允许以下来源:

  • ::1
  • 127.0.0.1
  • localhost
  • *.test
  • *.localhost
  • 项目 .env 中的 APP_URL

允许项目自定义来源的最简单方法是确保应用的 APP_URL 环境变量与你在浏览器中访问的来源匹配。例如,如果你访问的是 https://my-app.laravel,你应该更新 .env 使其匹配:

ini
APP_URL=https://my-app.laravel

如果你需要对来源进行更细粒度的控制,例如支持多个来源,你应该使用 Vite 全面而灵活的内置 CORS 服务器配置。例如,你可以在项目的 vite.config.js 文件中的 server.cors.origin 配置选项中指定多个来源:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
    ],
    server: {  // [tl! add]
        cors: {  // [tl! add]
            origin: [  // [tl! add]
                'https://backend.laravel',  // [tl! add]
                'http://admin.laravel:8566',  // [tl! add]
            ],  // [tl! add]
        },  // [tl! add]
    },  // [tl! add]
});

你还可以包含正则表达式模式,如果你想允许给定顶级域的所有来源(例如 *.laravel),这会很有帮助:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
    ],
    server: {  // [tl! add]
        cors: {  // [tl! add]
            origin: [ // [tl! add]
                // 支持: SCHEME://DOMAIN.laravel[:PORT] [tl! add]
                /^https?:\/\/.*\.laravel(:\d+)?$/, //[tl! add]
            ], // [tl! add]
        }, // [tl! add]
    }, // [tl! add]
});

修正开发服务器 URL

Vite 生态系统中的一些插件假设以正斜杠开头的 URL 始终指向 Vite 开发服务器。然而,由于 Laravel 集成的特性,情况并非如此。

例如,vite-imagetools 插件在 Vite 提供资源服务时输出如下 URL:

html
<img src="/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520">

vite-imagetools 插件期望输出 URL 将被 Vite 拦截,然后该插件可以处理所有以 /@imagetools 开头的 URL。如果你使用的插件期望这种行为,你将需要手动修正 URL。你可以在 vite.config.js 文件中使用 transformOnServe 选项来完成此操作。

在这个特定示例中,我们将在生成的代码中所有 /@imagetools 出现的位置前面添加开发服务器 URL:

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { imagetools } from 'vite-imagetools';

export default defineConfig({
    plugins: [
        laravel({
            // ...
            transformOnServe: (code, devServerUrl) => code.replaceAll('/@imagetools', devServerUrl+'/@imagetools'),
        }),
        imagetools(),
    ],
});

现在,当 Vite 提供资源服务时,它将输出指向 Vite 开发服务器的 URL:

html
- <img src="/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520"><!-- [tl! remove] -->
+ <img src="http://[::1]:5173/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520"><!-- [tl! add] -->