Vite是新一代的前端工具,可以直接从源头加载JS和CSS文件,不需要编译,并使用现代标准。
我相信有人很恼火,当他们在前台进行编辑时,必须进行不必要的编译和等待,然后每次进行编辑时都要反复运行编译。此外,系统往往需要以复杂的方式进行配置。幸运的是,由于现代的工具和方法,这种情况已经结束。
JavaScript模块可以通过多种方式加载,最著名的是CommonJS,你可以在Node.js中找到它。然而,这在浏览器中是行不通的,除非你使用一个像RequireJS这样的库。
一种在Node.js和浏览器中都适用的现代标准化格式是ES模块(ESM)。理论上,你可以用ES模块写源代码,并使用importmap,这将在浏览器中工作一次,无需编译任何东西。到目前为止,只有Chrome支持这个功能,对于其他浏览器,你需要使用es-module-shim。
Vite采取了类似的方法,完全使用ES模块--但目前还没有importmap。它使用esbuild来捆绑依赖性。这是用Go写的,构建速度比其他工具快10-100倍。然后本地服务器对模块的路径进行转换,使浏览器能够理解它们。目前,大多数库仍然是用CommonJS编写的,所以Vite将这些库转换为ESM语法,以便它们可以被浏览器加载。然后,它只在需要时才捆绑依赖性。不需要编译你自己的代码,它已经用浏览器能理解的现代ES格式写好了。
// source file
import { Application, Controller } from "@hotwired/stimulus";
顺便说一下,使用import-map,你可以按原样加载源代码,例如从CDNesm.sh中加载。这是一种替代方法,但Vite还不支持这种方法。
// loaded file in the browser (via Vite)
import { Application, Controller } from "/node_modules/.vite/@stimulus_core.js?v=02a6d100";
所以你直接从项目中的源文件加载JavaScript,不需要编译任何东西。Vite按需处理,用热模块替换(HMR)只编译改变的文件。Vite必须在后台运行,但如果你使用的是本地开发,这不是一个问题。它甚至可以在远程服务器上使用,CSS和JS从本地主机加载。
对于加载源文件,我们将创建一个简单的类来区分是加载源文件(开发)还是构建文件(生产)。
use Nette\Utils\FileSystem;
use Nette\Utils\Html;
use Nette\Utils\Json;
class ViteAssets
{
public function __construct(
private string $viteServer,
private string $manifestFile,
private bool $productionMode,
){}
public function printTags(string $entrypoint): void
{
$scripts = [];
$styles = [];
$baseUrl = '/';
if ($this->productionMode) {
if (file_exists($this->manifestFile)) {
$manifest = Json::decode(FileSystem::read($this->manifestFile), Json::FORCE_ARRAY);
$scripts = [$manifest[$entrypoint]['file']];
$styles = $manifest[$entrypoint]['css'] ?? [];
} else {
trigger_error('Missing manifest file: ' . $this->manifestFile, E_USER_WARNING);
}
} else {
$baseUrl = $this->viteServer . '/';
$scripts = ['@vite/client', $entrypoint];
}
foreach ($styles as $path) {
echo Html::el('link')->rel('stylesheet')->href($baseUrl . $path);
}
foreach ($scripts as $path) {
echo Html::el('script')->type('module')->src($baseUrl . $path);
}
}
}
简单地配置该类并将其传递给presenter。
services:
- ViteAssets(http://localhost:3000, %wwwDir%/manifest.json, not(%debugMode%))
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ViteAssets $viteAssets,
) {
}
public function beforeRender(): void
{
$this->template->viteAssets = $this->viteAssets;
}
}
并在布局模板中使用它。
{$viteAssets->printTags('src/main.js')}
我在GitHub上创建了一个Nette与Vite集成的例子,基于web-project。
我为Vite添加了一个Tracy扩展,你可以使用一个图标来切换通过Vite的加载,基于浏览器中存储的cookie。

对于本地开发,有一个由Josef Jebavy添加的Docker Image。 所以你只需要安装Docker和Node.js 14+,实际上你的系统不需要PHP和Composer。然后我添加了以下库作为前端的启动包。
首先,使用npm i 安装Node.js包的依赖项。安装后,使用docker compose up 启动本地Web服务器,使用npm run dev 启动Vite。
Vite也使用Web Sockets,因此.php 、.latte 或.css 、.js 文件的任何变化都会自动重新加载浏览器并检索当前数据。
对于生产来说,它然后运行npm run build ,将JS和CSS源文件构建到www/assets ,并将manifest.json ,将每个文件的修订版添加到www。
这实际上是一个与Laravel Vite非常相似的方法
Vite是在项目的vite.config.js 文件中配置的,基本配置看起来像这样。
export default {
build: {
manifest: true,
outDir: "www",
emptyOutDir: false,
rollupOptions: {
input: '/src/scripts/main.js'
}
}
}
Vite目前唯一的缺点是,CSS文件必须包含在JS (import "/src/styles/main.css")中才能构建。因此,它们在构建时确实被分开了,但有些人可能会对这种记号感到困扰。CSS也可以通过<link rel="stylesheet" href="src/styles/main.css"> 直接链接。如果你这样做,你仍然需要在JS中包含它们以创建一个清单条目。例如,你可以使用这样的一个黑客。
if (typeof window[9999] !== 'undefined') {
(async() => await import('/src/styles/main.css'))()
}
谁也不喜欢这两种解决方案,所以别无选择,只能等待这个问题的解决--github.com/.../issues/…另外,也可以使用gulp-vite进行构建,构建可以通过Gulp和Esbuild来处理,而Vite可以用来允许从source、Web Sockets等加载东西。
我们已经在Newlogic Core等项目中使用了这种方法,Vite被用作本地服务器,其他一切都由Gulp处理。这个项目的想法是将所有的现代开发工具--如PostCSS、PurgeCSS、Tailwind等等。- 在一个软件包中。在GitHub上整合Newlogic Core与Nette的例子
如果你使用Vite、Stimulus和Naja与Nette的组合,你会得到一个现代的、易于管理的前端。关于如何使用Vite和现代前端方法的全面演示,我也推荐你查看Newlogic UI。
如果有人对过去10年的前端工具的比较以及我们如何开发Newlogic Core & UI感兴趣,可以查看这篇文章。