Filament 生态系统中的所有包都共享一个资产管理系统。这使得官方插件和第三方插件都能够注册 CSS 和 JavaScript 文件,这些文件随后可被 Blade 视图使用。
FilamentAsset 外观FilamentAsset facade 用于将文件注册到资产系统中。这些文件可能来源于文件系统中的任何位置,但当运行 php artisan filament:assets 命令时,它们会被复制到应用程序的 /public 目录中。通过为您将它们复制到 /public 目录中,我们可以可预测地在 Blade 视图中加载它们,并且还能确保第三方包能够加载它们的资产,而无需担心它们位于何处。
资产始终具有您选择的唯一ID,该ID用作文件名,当资产被复制到 /public 目录时。此ID也用于在 Blade 视图中引用资产。虽然ID是唯一的,但如果您正在为插件注册资产,那么您无需担心ID与其他插件冲突,因为资产将被复制到以您的插件命名的目录中。
FilamentAsset facade 应在服务提供者的 boot() 方法中使用。它可以在应用程序服务提供者(例如 AppServiceProvider)中,或在插件服务提供者中使用。
该 FilamentAsset 外观有一个主要方法,register(),它接受一个要注册的资产数组:
use Filament\Support\Facades\FilamentAsset;
public function boot(): void
{
// ...
FilamentAsset::register([
// ...
]);
// ...
}当为插件注册资产时,您应该将 Composer 包的名称作为 register() 方法的第二个参数传递:
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::register([
// ...
], package: 'danharrin/filament-blog');现在,此插件的所有资产都将被复制到 /public 内部的一个独立目录中,以避免与具有相同名称的其他插件文件发生冲突的可能性。
要向资产系统注册 CSS 文件,请在服务提供者的 boot() 方法中使用 FilamentAsset::register() 方法。你必须传入一个 Css 对象数组,其中每个对象代表一个应该在资产系统中注册的 CSS 文件。
每一个 Css 对象都具有唯一的 ID 以及一个指向 CSS 文件的路径:
use Filament\Support\Assets\Css;
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::register([
Css::make('custom-stylesheet', __DIR__ . '/../../resources/css/custom.css'),
]);在此示例中,我们使用 __DIR__ 来生成一个从当前文件到资源的相对路径。例如,如果您将此代码添加到 /app/Providers/AppServiceProvider.php,那么 CSS 文件应该存在于 /resources/css/custom.css。
现在,当运行 php artisan filament:assets 命令时,这个 CSS 文件会被复制到 /public 目录中。此外,它现在会被加载到所有使用 Filament 的 Blade 视图中。如果您只希望在页面元素需要时才加载 CSS,请查看 懒加载 CSS 部分。
通常情况下,注册 CSS 文件用于为你的应用程序注册自定义样式表。如果你想使用 Tailwind CSS 处理这些文件,你需要考虑其影响,特别是如果你是一名插件开发者。
Tailwind 构建对于每个应用程序都是独一无二的 - 它们包含一套最少的实用工具类,仅包含您在应用程序中实际使用的那些。这意味着,如果您是插件开发者,您可能不应该将您的 Tailwind CSS 文件构建到您的插件中。相反,您应该提供原始 CSS 文件,并指示用户他们应该自行构建 Tailwind CSS 文件。为此,他们需要使用 @source 指令将您的 vendor 目录添加到他们自定义主题的 CSS 文件中。在他们的 自定义主题 CSS 文件中 (例如,resources/css/filament/admin/theme.css),他们应该添加:
@import "tailwindcss";
@source '../../../../app/Filament';
@source '../../../../resources/views/filament';
@source '../../../../vendor/danharrin/filament-blog/resources/views'; /* Your plugin's vendor directory */这意味着当他们构建他们的 Tailwind CSS 文件时,它将包含在你的插件视图中使用的所有实用工具类,以及在他们的应用程序和 Filament 核心中使用的实用工具类。
然而,使用这种技术,对于将您的插件与 面板构建器 一起使用的用户,可能会出现额外的复杂情况。如果他们有 自定义主题,他们会没问题,因为他们无论如何都在使用 Tailwind CSS 构建自己的 CSS 文件。然而,如果他们正在使用面板构建器附带的默认样式表,您可能需要注意在插件视图中使用的工具类。例如,如果您使用一个未包含在默认样式表中的工具类,用户不会自己编译它,它也不会包含在最终的 CSS 文件中。这意味着您的插件视图可能不会如预期显示。这是少数几种我会推荐在您的插件中编译并 注册 一个 Tailwind CSS 编译好的样式表的情况。
默认情况下,所有通过资源系统注册的 CSS 文件都会被加载到每个 Filament 页面的 <head> 中。这是加载 CSS 文件最简单的方式,但有时它们可能相当庞大,并且并非每个页面都必需。在这种情况下,你可以利用随 Filament 一起提供的 Alpine.js Lazy Load Assets 包。它允许你使用 Alpine.js 轻松地按需加载 CSS 文件。其原理非常简单,你在一个元素上使用 x-load-css 指令,当该元素加载到页面上时,指定的 CSS 文件就会被加载到页面的 <head> 中。这非常适合小型 UI 元素以及需要 CSS 文件的整个页面:
<div
x-data="{}"
x-load-css="[@js(\Filament\Support\Facades\FilamentAsset::getStyleHref('custom-stylesheet'))]"
>
<!-- ... -->
</div>为了防止 CSS 文件自动加载,你可以使用 loadedOnRequest() 方法:
use Filament\Support\Assets\Css;
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::register([
Css::make('custom-stylesheet', __DIR__ . '/../../resources/css/custom.css')->loadedOnRequest(),
]);如果您的 CSS 文件已注册到插件,您必须将其作为第二个参数传递给 FilamentAsset::getStyleHref() 方法:
<div
x-data="{}"
x-load-css="[@js(\Filament\Support\Facades\FilamentAsset::getStyleHref('custom-stylesheet', package: 'danharrin/filament-blog'))]"
>
<!-- ... -->
</div>如果您想从 URL 注册 CSS 文件,您可以这样做。这些资源将正常加载到每个页面,但在运行 php artisan filament:assets 命令时不会复制到 /public 目录中。这对于从 CDN 注册外部样式表,或注册您已直接编译到 /public 目录中的样式表很有用:
use Filament\Support\Assets\Css;
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::register([
Css::make('example-external-stylesheet', 'https://example.com/external.css'),
Css::make('example-local-stylesheet', asset('css/local.css')),
]);有时,您可能希望在 CSS 文件中使用来自后端的动态数据。 为此,您可以使用 FilamentAsset::registerCssVariables() 方法,在服务提供者的 boot() 方法中:
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::registerCssVariables([
'background-image' => asset('images/background.jpg'),
]);现在,你可以从任何 CSS 文件访问这些变量:
background-image: var(--background-image);要向资产系统注册 JavaScript 文件,请在服务提供商的 boot() 方法中使用 FilamentAsset::register() 方法。您必须传入一个 Js 对象数组,每个对象都代表一个应在资产系统中注册的 JavaScript 文件。
每个 Js 对象拥有一个唯一的 ID 以及一个指向 JavaScript 文件的路径:
use Filament\Support\Assets\Js;
FilamentAsset::register([
Js::make('custom-script', __DIR__ . '/../../resources/js/custom.js'),
]);在此示例中,我们使用 __DIR__ 从当前文件生成一个到资源的相对路径。例如,如果您将此代码添加到 /app/Providers/AppServiceProvider.php,那么 JavaScript 文件应该存在于 /resources/js/custom.js 中。
现在,当 php artisan filament:assets 命令运行时,这个 JavaScript 文件会被复制到 /public 目录中。此外,它现在会被加载到所有使用 Filament 的 Blade 视图中。如果你有兴趣只在页面上的元素需要时才加载 JavaScript,请查看 惰性加载 JavaScript 部分。
默认情况下,所有在资产系统中注册的 JavaScript 文件都会加载到每个 Filament 页面的底部。这是加载 JavaScript 文件最简单的方法,但有时它们可能相当庞大且并非每个页面都需要。在这种情况下,您可以利用 Filament 捆绑的 Alpine.js 懒加载资产 包。它允许您使用 Alpine.js 轻松按需加载 JavaScript 文件。其前提非常简单,您在一个元素上使用 x-load-js 指令,当该元素加载到页面上时,指定的 JavaScript 文件就会加载到页面底部。这对于需要 JavaScript 文件的小型 UI 元素和整个页面都非常适用:
<div
x-data="{}"
x-load-js="[@js(\Filament\Support\Facades\FilamentAsset::getScriptSrc('custom-script'))]"
>
<!-- ... -->
</div>为了防止 JavaScript 文件自动加载,您可以使用 loadedOnRequest() 方法:
use Filament\Support\Assets\Js;
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::register([
Js::make('custom-script', __DIR__ . '/../../resources/js/custom.js')->loadedOnRequest(),
]);如果你的 JavaScript 文件被 注册到一个插件, 你必须将其作为第二个参数传递给 FilamentAsset::getScriptSrc() 方法:
<div
x-data="{}"
x-load-js="[@js(\Filament\Support\Facades\FilamentAsset::getScriptSrc('custom-script', package: 'danharrin/filament-blog'))]"
>
<!-- ... -->
</div>有时,您可能希望为基于 Alpine.js 的组件加载外部 JavaScript 库。实现此目的的最佳方式是将编译后的 JavaScript 和 Alpine 组件存储在一个单独的文件中,并让我们在组件渲染时加载它。
首先,你应该安装 esbuild 通过 NPM,我们将用它来创建一个包含你的外部库和 Alpine 组件的单一 JavaScript 文件:
npm install esbuild --save-dev然后,您必须创建一个脚本来编译您的 JavaScript 和 Alpine 组件。您可以将其放在任何位置,例如 bin/build.js:
import * as esbuild from 'esbuild'
const isDev = process.argv.includes('--dev')
async function compile(options) {
const context = await esbuild.context(options)
if (isDev) {
await context.watch()
} else {
await context.rebuild()
await context.dispose()
}
}
const defaultOptions = {
define: {
'process.env.NODE_ENV': isDev ? `'development'` : `'production'`,
},
bundle: true,
mainFields: ['module', 'main'],
platform: 'neutral',
sourcemap: isDev ? 'inline' : false,
sourcesContent: isDev,
treeShaking: true,
target: ['es2020'],
minify: !isDev,
plugins: [{
name: 'watchPlugin',
setup(build) {
build.onStart(() => {
console.log(`Build started at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`)
})
build.onEnd((result) => {
if (result.errors.length > 0) {
console.log(`Build failed at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`, result.errors)
} else {
console.log(`Build finished at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`)
}
})
}
}],
}
compile({
...defaultOptions,
entryPoints: ['./resources/js/components/test-component.js'],
outfile: './resources/js/dist/components/test-component.js',
})正如你可以在脚本底部看到的,我们正在将一个名为 resources/js/components/test-component.js 的文件编译到 resources/js/dist/components/test-component.js 中。你可以根据自己的需要更改这些路径。你可以编译任意数量的组件。
现在,创建一个新文件,命名为 resources/js/components/test-component.js:
// Import any external JavaScript libraries from NPM here.
export default function testComponent({
state,
}) {
return {
state,
// You can define any other Alpine.js properties here.
init() {
// Initialise the Alpine component here, if you need to.
},
// You can define any other Alpine.js functions here.
}
}现在,您可以将此文件编译到 resources/js/dist/components/test-component.js,方法是运行以下命令:
node bin/build.js如果你想监视此文件的更改而不是只编译一次,请尝试以下命令:
node bin/build.js --dev现在,你需要告诉 Filament 发布这个编译后的 JavaScript 文件到 Laravel 应用程序的 /public 目录中,以便浏览器可以访问它。为此,你可以在服务提供者的 boot() 方法中使用 FilamentAsset::register() 方法,传入一个 AlpineComponent 对象:
use Filament\Support\Assets\AlpineComponent;
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::register([
AlpineComponent::make('test-component', __DIR__ . '/../../resources/js/dist/components/test-component.js'),
]);当你运行 php artisan filament:assets,编译后的文件将被复制到 /public 目录。
最后,您可以在您的视图中使用 x-load 属性和 FilamentAsset::getAlpineComponentSrc() 方法加载这个异步的 Alpine 组件:
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('test-component') }}"
x-data="testComponent({
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})"
>
<input x-model="state" />
</div>这个例子是针对一个自定义表单字段的。它将state作为参数传递给testComponent()函数,该函数与一个Livewire组件属性相关联。你可以传递任何你想要的参数,并在testComponent()函数中访问它们。如果你没有使用自定义表单字段,你可以忽略本例中的state参数。
x-load 属性来自 Async Alpine 包,并且该包的任何功能都可以在这里使用。
有时,您可能希望将后端数据提供给 JavaScript 文件。
为此,您可以在服务提供者的 boot() 方法中使用 FilamentAsset::registerScriptData() 方法:
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::registerScriptData([
'user' => [
'name' => auth()->user()?->name,
],
]);现在,您可以在运行时从任何 JavaScript 文件访问这些数据,使用 window.filamentData 对象:
window.filamentData.user.name // 'Dan Harrin'如果你想从 URL 注册一个 JavaScript 文件,你可以这样做。这些资源将像往常一样在每个页面上加载,但当 php artisan filament:assets 命令运行时,不会复制到 /public 目录中。这对于从 CDN 注册外部脚本,或者你已经直接编译到 /public 目录中的脚本非常有用:
use Filament\Support\Assets\Js;
FilamentAsset::register([
Js::make('example-external-script', 'https://example.com/external.js'),
Js::make('example-local-script', asset('js/local.js')),
]);