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 插件。使用不受信任的证书时,您需要在浏览器中接受 Vite 开发服务器的证书警告,方法是在运行 npm run dev 命令时按照控制台中的「Local」链接操作。

在 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 门面提供的 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 处理。然后,您可以使用 Vite::asset 方法在 Blade 模板中引用这些资源,该方法将返回给定资源的版本化 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/**'],
        }),
    ],
});

别名

如果在 Blade 中使用别名,您可能需要配置 Vite 以正确解析这些别名。请参阅上文的别名配置部分。

资源预取

当使用 Inertia 和 Vite 的代码分割功能时,建议在页面首次加载时预取 JavaScript 块。这可以通过在应用程序的 vite.config.js 文件中配置 prefetch 选项来实现:

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

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

prefetch 选项指定应该预取多少个块。默认情况下,预取是禁用的。

自定义基础 URL

如果您的资源部署到与应用程序不同的域,您可以在应用程序的 .env 文件中指定 ASSET_URL 环境变量:

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

配置此值后,Vite 将在生成资源 URL 时添加配置的 URL 前缀:

blade
<script src="https://cdn.example.com/build/assets/app.12345.js"></script>

环境变量

您可以通过在应用程序的 .env 文件中定义 VITE_ 前缀的环境变量,将环境变量注入 JavaScript:

env
VITE_SENTRY_DSN_PUBLIC=https://example.com

然后,您可以在 JavaScript 中通过 import.meta.env 对象访问这些变量:

js
const dsn = import.meta.env.VITE_SENTRY_DSN_PUBLIC;

在测试中禁用 Vite

Laravel 的 Vite 集成会在测试期间尝试解析您的资源,这可能会减慢测试速度。如果您想在测试中禁用 Vite,您可以在 phpunit.xml 文件中添加 VITE_DISABLED 环境变量:

xml
<env name="VITE_DISABLED" value="true"/>

服务端渲染 (SSR)

Laravel Vite 插件可以轻松地与服务端渲染 (SSR) 设置集成。首先,您应该在 vite.config.js 中指定 SSR 入口点:

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',
        }),
    ],
});

然后,您可以使用 @vite 指令的第二个参数指定 SSR 构建目录:

blade
@vite('resources/js/app.js', 'ssr')

脚本和样式标签属性

内容安全策略 (CSP) Nonce

如果您的内容安全策略要求脚本和样式具有 nonce,您可以在应用程序的 AppServiceProvider 中使用 useNonce 方法:

php
use Illuminate\Support\Facades\Vite;

/**
 * 引导任何应用程序服务。
 */
public function boot(): void
{
    Vite::useNonce('your-nonce-value');
}

然后,Vite 将在生成的脚本和样式标签中包含 nonce 属性:

html
<script nonce="your-nonce-value" src="..."></script>

子资源完整性 (SRI)

如果您想为资源启用子资源完整性 (SRI),您可以在应用程序的 AppServiceProvider 中使用 useIntegrity 方法:

php
use Illuminate\Support\Facades\Vite;

/**
 * 引导任何应用程序服务。
 */
public function boot(): void
{
    Vite::useIntegrity();
}

这将自动为所有资源生成并包含 integrity 属性。

任意属性

如果您需要向生成的脚本或样式标签添加任意属性,可以使用 useScriptTagAttributesuseStyleTagAttributes 方法:

php
use Illuminate\Support\Facades\Vite;

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

Vite::useStyleTagAttributes([
    'media' => 'print',
]);

高级自定义

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

如果您需要自定义开发服务器的 CORS 设置,可以在 vite.config.js 文件中配置:

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

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

修正开发服务器 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 选项来完成此操作。

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

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] -->