webui: Static build output improvements (#21667)
* refactor: Build improvements * chore: Formatting + package lock update
This commit is contained in:
+12781
-195
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
This is a single file build of the frontend.
|
This is a static build of the frontend.
|
||||||
It is automatically generated by the build process.
|
It is automatically generated by the build process.
|
||||||
Do not edit this file directly.
|
Do not edit this file directly.
|
||||||
To make changes, refer to the "Web UI" section in the README.
|
To make changes, refer to the "Web UI" section in the README.
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<div style="display: contents">
|
<div style="display: contents">
|
||||||
<script>
|
<script>
|
||||||
{
|
{
|
||||||
__sveltekit_1ao0o9h = {
|
__sveltekit__ = {
|
||||||
base: new URL('.', location).pathname.slice(0, -1)
|
base: new URL('.', location).pathname.slice(0, -1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "webui",
|
"name": "llama-server-webui",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "webui",
|
"name": "llama-server-webui",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.25.1",
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "webui",
|
"name": "llama-server-webui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import { readFileSync, writeFileSync, existsSync, readdirSync, copyFileSync } from 'fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import type { Plugin } from 'vite';
|
||||||
|
|
||||||
|
const GUIDE_FOR_FRONTEND = `
|
||||||
|
<!--
|
||||||
|
This is a static build of the frontend.
|
||||||
|
It is automatically generated by the build process.
|
||||||
|
Do not edit this file directly.
|
||||||
|
To make changes, refer to the "Web UI" section in the README.
|
||||||
|
-->
|
||||||
|
`.trim();
|
||||||
|
|
||||||
|
export function llamaCppBuildPlugin(): Plugin {
|
||||||
|
return {
|
||||||
|
name: 'llamacpp:build',
|
||||||
|
apply: 'build',
|
||||||
|
closeBundle() {
|
||||||
|
// Ensure the SvelteKit adapter has finished writing to ../public
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
const indexPath = resolve('../public/index.html');
|
||||||
|
if (!existsSync(indexPath)) return;
|
||||||
|
|
||||||
|
let content = readFileSync(indexPath, 'utf-8');
|
||||||
|
|
||||||
|
const faviconPath = resolve('static/favicon.svg');
|
||||||
|
|
||||||
|
if (existsSync(faviconPath)) {
|
||||||
|
const faviconContent = readFileSync(faviconPath, 'utf-8');
|
||||||
|
const faviconBase64 = Buffer.from(faviconContent).toString('base64');
|
||||||
|
const faviconDataUrl = `data:image/svg+xml;base64,${faviconBase64}`;
|
||||||
|
|
||||||
|
content = content.replace(/href="[^"]*favicon\.svg"/g, `href="${faviconDataUrl}"`);
|
||||||
|
|
||||||
|
console.log('✓ Inlined favicon.svg as base64 data URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
content = content.replace(/\r/g, '');
|
||||||
|
content = GUIDE_FOR_FRONTEND + '\n' + content;
|
||||||
|
content = content.replace(/\/_app\/immutable\/bundle\.[^"]+\.js/g, './bundle.js');
|
||||||
|
content = content.replace(
|
||||||
|
/\/_app\/immutable\/assets\/bundle\.[^"]+\.css/g,
|
||||||
|
'./bundle.css'
|
||||||
|
);
|
||||||
|
content = content.replace(/__sveltekit_[a-z0-9]+/g, '__sveltekit__');
|
||||||
|
|
||||||
|
writeFileSync(indexPath, content, 'utf-8');
|
||||||
|
console.log('✓ Updated index.html');
|
||||||
|
|
||||||
|
// Copy bundle.*.js -> ../public/bundle.js
|
||||||
|
const immutableDir = resolve('../public/_app/immutable');
|
||||||
|
const bundleDir = resolve('../public/_app/immutable/assets');
|
||||||
|
|
||||||
|
if (existsSync(immutableDir)) {
|
||||||
|
const jsFiles = readdirSync(immutableDir).filter((f) => f.match(/^bundle\..+\.js$/));
|
||||||
|
|
||||||
|
if (jsFiles.length > 0) {
|
||||||
|
copyFileSync(resolve(immutableDir, jsFiles[0]), resolve('../public/bundle.js'));
|
||||||
|
// Normalize __sveltekit_<hash> to __sveltekit__ in bundle.js
|
||||||
|
const bundleJsPath = resolve('../public/bundle.js');
|
||||||
|
let bundleJs = readFileSync(bundleJsPath, 'utf-8');
|
||||||
|
bundleJs = bundleJs.replace(/__sveltekit_[a-z0-9]+/g, '__sveltekit__');
|
||||||
|
writeFileSync(bundleJsPath, bundleJs, 'utf-8');
|
||||||
|
console.log(`✓ Copied ${jsFiles[0]} -> bundle.js`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy bundle.*.css -> ../public/bundle.css
|
||||||
|
if (existsSync(bundleDir)) {
|
||||||
|
const cssFiles = readdirSync(bundleDir).filter((f) => f.match(/^bundle\..+\.css$/));
|
||||||
|
|
||||||
|
if (cssFiles.length > 0) {
|
||||||
|
copyFileSync(resolve(bundleDir, cssFiles[0]), resolve('../public/bundle.css'));
|
||||||
|
console.log(`✓ Copied ${cssFiles[0]} -> bundle.css`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to update index.html:', error);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -22,7 +22,8 @@
|
|||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p class="text-xs text-muted-foreground">
|
<p class="text-xs text-muted-foreground">
|
||||||
Press <kbd class="rounded bg-muted px-1 py-0.5 font-mono text-xs">{modKey} + Enter</kbd> to send,
|
Press <kbd class="rounded bg-muted px-1 py-0.5 font-mono text-xs">{modKey} + Enter</kbd> to
|
||||||
|
send,
|
||||||
<kbd class="rounded bg-muted px-1 py-0.5 font-mono text-xs">Enter</kbd> for new line
|
<kbd class="rounded bg-muted px-1 py-0.5 font-mono text-xs">Enter</kbd> for new line
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ const config = {
|
|||||||
},
|
},
|
||||||
alias: {
|
alias: {
|
||||||
$styles: 'src/styles'
|
$styles: 'src/styles'
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
name: 'llama-server-webui'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,108 +1,33 @@
|
|||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { readFileSync, writeFileSync, existsSync, readdirSync, copyFileSync } from 'fs';
|
|
||||||
import { dirname, resolve } from 'path';
|
import { dirname, resolve } from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
import { defineConfig, searchForWorkspaceRoot } from 'vite';
|
import { defineConfig, searchForWorkspaceRoot } from 'vite';
|
||||||
import devtoolsJson from 'vite-plugin-devtools-json';
|
import devtoolsJson from 'vite-plugin-devtools-json';
|
||||||
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
|
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
|
||||||
|
import { llamaCppBuildPlugin } from './scripts/vite-plugin-llama-cpp-build';
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
const GUIDE_FOR_FRONTEND = `
|
|
||||||
<!--
|
|
||||||
This is a single file build of the frontend.
|
|
||||||
It is automatically generated by the build process.
|
|
||||||
Do not edit this file directly.
|
|
||||||
To make changes, refer to the "Web UI" section in the README.
|
|
||||||
-->
|
|
||||||
`.trim();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the maximum size of an embedded asset in bytes,
|
|
||||||
* e.g. maximum size of embedded font (see node_modules/katex/dist/fonts/*.woff2)
|
|
||||||
*/
|
|
||||||
const MAX_ASSET_SIZE = 32000;
|
|
||||||
|
|
||||||
/** public/index.html minified flag */
|
|
||||||
const ENABLE_JS_MINIFICATION = true;
|
|
||||||
|
|
||||||
function llamaCppBuildPlugin() {
|
|
||||||
return {
|
|
||||||
name: 'llamacpp:build',
|
|
||||||
apply: 'build' as const,
|
|
||||||
closeBundle() {
|
|
||||||
// Ensure the SvelteKit adapter has finished writing to ../public
|
|
||||||
setTimeout(() => {
|
|
||||||
try {
|
|
||||||
const indexPath = resolve('../public/index.html');
|
|
||||||
|
|
||||||
if (!existsSync(indexPath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let content = readFileSync(indexPath, 'utf-8');
|
|
||||||
|
|
||||||
const faviconPath = resolve('static/favicon.svg');
|
|
||||||
if (existsSync(faviconPath)) {
|
|
||||||
const faviconContent = readFileSync(faviconPath, 'utf-8');
|
|
||||||
const faviconBase64 = Buffer.from(faviconContent).toString('base64');
|
|
||||||
const faviconDataUrl = `data:image/svg+xml;base64,${faviconBase64}`;
|
|
||||||
|
|
||||||
content = content.replace(/href="[^"]*favicon\.svg"/g, `href="${faviconDataUrl}"`);
|
|
||||||
|
|
||||||
console.log('✓ Inlined favicon.svg as base64 data URL');
|
|
||||||
}
|
|
||||||
|
|
||||||
content = content.replace(/\r/g, '');
|
|
||||||
content = GUIDE_FOR_FRONTEND + '\n' + content;
|
|
||||||
content = content.replace(/\/_app\/immutable\/bundle\.[^"]+\.js/g, './bundle.js');
|
|
||||||
content = content.replace(
|
|
||||||
/\/_app\/immutable\/assets\/bundle\.[^"]+\.css/g,
|
|
||||||
'./bundle.css'
|
|
||||||
);
|
|
||||||
|
|
||||||
writeFileSync(indexPath, content, 'utf-8');
|
|
||||||
console.log('✓ Updated index.html');
|
|
||||||
|
|
||||||
// Copy bundle.*.js -> ../public/bundle.js
|
|
||||||
const immutableDir = resolve('../public/_app/immutable');
|
|
||||||
const bundleDir = resolve('../public/_app/immutable/assets');
|
|
||||||
if (existsSync(immutableDir)) {
|
|
||||||
const jsFiles = readdirSync(immutableDir).filter((f) => f.match(/^bundle\..+\.js$/));
|
|
||||||
if (jsFiles.length > 0) {
|
|
||||||
copyFileSync(resolve(immutableDir, jsFiles[0]), resolve('../public/bundle.js'));
|
|
||||||
console.log(`✓ Copied ${jsFiles[0]} -> bundle.js`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Copy bundle.*.css -> ../public/bundle.css
|
|
||||||
if (existsSync(bundleDir)) {
|
|
||||||
const cssFiles = readdirSync(bundleDir).filter((f) => f.match(/^bundle\..+\.css$/));
|
|
||||||
if (cssFiles.length > 0) {
|
|
||||||
copyFileSync(resolve(bundleDir, cssFiles[0]), resolve('../public/bundle.css'));
|
|
||||||
console.log(`✓ Copied ${cssFiles[0]} -> bundle.css`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to update index.html:', error);
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'katex-fonts': resolve('node_modules/katex/dist/fonts')
|
'katex-fonts': resolve('node_modules/katex/dist/fonts')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
build: {
|
build: {
|
||||||
assetsInlineLimit: MAX_ASSET_SIZE,
|
assetsInlineLimit: 32000,
|
||||||
chunkSizeWarningLimit: 3072,
|
chunkSizeWarningLimit: 3072,
|
||||||
minify: ENABLE_JS_MINIFICATION
|
minify: true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
esbuild: {
|
||||||
|
lineLimit: 500,
|
||||||
|
minifyIdentifiers: false
|
||||||
|
},
|
||||||
|
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
scss: {
|
scss: {
|
||||||
@@ -114,7 +39,9 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: [tailwindcss(), sveltekit(), devtoolsJson(), llamaCppBuildPlugin()],
|
plugins: [tailwindcss(), sveltekit(), devtoolsJson(), llamaCppBuildPlugin()],
|
||||||
|
|
||||||
test: {
|
test: {
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
@@ -131,6 +58,7 @@ export default defineConfig({
|
|||||||
setupFiles: ['./vitest-setup-client.ts']
|
setupFiles: ['./vitest-setup-client.ts']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
extends: './vite.config.ts',
|
extends: './vite.config.ts',
|
||||||
test: {
|
test: {
|
||||||
@@ -139,6 +67,7 @@ export default defineConfig({
|
|||||||
include: ['tests/unit/**/*.{test,spec}.{js,ts}']
|
include: ['tests/unit/**/*.{test,spec}.{js,ts}']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
extends: './vite.config.ts',
|
extends: './vite.config.ts',
|
||||||
test: {
|
test: {
|
||||||
|
|||||||
Reference in New Issue
Block a user