高级
注册静态资源
介绍
Filament 生态系统中的所有包都共享同一个资源管理系统。它允许官方插件及第三方插件注册用于 Blade 视图的 CSS 和 JavaScript 文件。
FilamentAsset
Facade
FilamentAsset
Facade 用于将文件注册到资源系统。这些文件可以来自于文件系统的任何地方,之后当运行 php artisan filament:assets
命令时,它们将被复制到应用的 public
目录中。通过将它们复制到 public
目录,我们可以在 Blade 视图中可预测地加载它们,同时确保第三方包也能够加载它们的资源,而不必操心资源所在的位置。
资源始终有一个由你确定的唯一 ID,当资源被复制到 /public
目录时,该 ID 将被用作文件名。此 ID 还用于在 Blade 视图中引用资源。虽然 ID 是唯一的,但如果你正在为插件注册资源,则不必担心 ID 会与其他插件冲突,因为资源将被复制到以你的插件命名的目录中。
FilamentAsset
Facade 应该在服务提供者的 boot()
方法中使用。它可用于应用服务提供者(如 AppServiceProvider
)之中,也可用于插件的服务提供者内。
FilamentAsset
Facade 有一个主方法: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 文件
要在资源系统中注册 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部分。
在插件中使用 Tailwind CSS
通常,注册 CSS 文件用在应用的自定义样式表。如果你想使用 Tailwind CSS 处理这些文件,你需要考虑其影响,特别是如果你是一名插件开发者
Tailwind 编译对于每个应用都是唯一的 —— 它们包含一套最小化的实用类,只有你在应用中实际使用到的那些类。这意味着,如果你是一名插件开发者,你可能不应该将 Tailwind CSS 文件构建到你的插件中。相反,你应该提供原始 CSS 文件,并指示用户自己构建 Tailwind CSS 文件。为此,他们可能只需要将你的 vendor 目录添加到他们的 tailwind.config.js
文件的 content
数组中:
export default {
content: [
'./resources/**/*.blade.php',
'./vendor/filament/**/*.blade.php',
'./vendor/danharrin/filament-blog/resources/views/**/*.blade.php', // Your plugin's vendor directory
],
// ...
}
也就是说当他们编译他们自己的 Tailwind CSS 文件时,它将包含所有你插件视图中用到的实用(utility)类,以及他自己应用中和 Filament 核心中用到的实用类。
不过,使用这一技术,对于使用你插件的[面板构建器]用户来说,可能会有额外的复杂性。如果他们有自己的自定义主题,则没什么影响,因为他们无论如何都在使用 Tailwind CSS 构建自己的 CSS 文件。但是,如果他们使用的是面板生成器附带的默认样式表,你可能需要小心留意在插件视图中使用的实用类。比如,如果你使用了默认样式表中未曾使用过的实用类,而用户又没有自己编译,那么这些类就没有包含在最终的 CSS 文件中。也就是说你的插件视图外观可能不如预期那般展示。这是推荐在插件中编译和注册 Tailwind css 编译过的样式表的少数几种情况之一。
懒加载 CSS
默认情况下,使用资源系统注册的所有 CSS 文件都会在每一个 Filament 页面的 <head>
中加载。这是加载 CSS 文件的最简单方式,不过有时候这种方式可能偏于繁重,而且不是每个页面都需要它。这种情况下,你可以利用 Filament 中捆绑的 Alpine.js 懒加载资源包。它允许你使用 Alpine.js 按需加载 CSS 文件。引导很简单,你可以在元素上使用 x-load-css
指令,当该元素加载到页面上时,指定的 css 文件将加载到页面的 <head>
中。这对于需要 CSS 文件的小 UI 元素和整个页面来说都是完美的:
<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 文件
如果你想注册一个基于 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 变量
有时,你可能希望在 CSS 文件中使用来自于后端的动态数据。为此,你可以在服务提供者的 boot()
中调用 FilamentAsset::registerCssVariables()
方法:
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::registerCssVariables([
'background-image' => asset('images/background.jpg'),
]);
现在,你可以在 CSS 文件中访问这些变量:
background-image: var(--background-image);
注册 JavaScript 文件
想要使用资源系统注册 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
默认情况下,使用资源系统注册的所有 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 组件
有时,你可能希望为基于 Alpine.js 的组件加载外部 JavaScript 库。最好的方法是将编译后的 JavaScript 和 Alpine 组件存储在一个单独的文件中,并让我们在渲染组件时加载它。
首先,你应该通过 npm 安装 esbuild,我们将使用它创建一个包含外部库和 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
,如下:
// 从 NPM 导入外部 JavaScript 库
export default function testComponent({
state,
}) {
return {
state,
// 你可以在此处定义其他 Alpine.js 属性
init() {
// 根据需要在此处初始化 Alpine 组件
},
// 你可以在此处定义其他 Alpine.js 函数
}
}
然后,运行如下命令,将该文件编译到 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 组件属性绑定(entangle)。你可以传入任何你想要的参数,并在 testComponent()
函数中访问。如果你未使用自定义表单字段,你可以在本示例中忽视 state
参数。
x-load
属性来自于异步 Alpine包,该包的所有特性都可以在此处使用。
注册脚本数据
有时,你可能希望让后端数据可用于 JavaScript 文件中。为此,你可以在服务提供者的 boot()
中调用 FilamentAsset::registerScriptData()
方法:
use Filament\Support\Facades\FilamentAsset;
FilamentAsset::registerScriptData([
'user' => [
'name' => auth()->user()?->name,
],
]);
现在,你可以使用 window.filamentData
对象,在运行时从 JavaScript 文件中访问这些数据:
window.filamentData.user.name // 'Dan Harrin'
使用 URL 注册 JavaScript 文件
如果你想注册一个基于 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')),
]);
Edit on GitHubStill need help? Join our Discord community or open a GitHub discussion