mirror of
https://github.com/chenasraf/nextcloud-app-template.git
synced 2026-05-17 17:28:09 +00:00
build: improve chunking strategy & asset loading
This commit is contained in:
@@ -29,6 +29,33 @@ class Application extends App implements IBootstrap {
|
|||||||
public function boot(IBootContext $context): void {
|
public function boot(IBootContext $context): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to parse Vite Manifest
|
||||||
|
*/
|
||||||
|
public static function getViteEntryScript(string $entryName): string {
|
||||||
|
$jsDir = realpath(__DIR__ . '/../' . Application::JS_DIR);
|
||||||
|
$manifestPath = dirname($jsDir) . '/.vite/manifest.json';
|
||||||
|
|
||||||
|
if (!file_exists($manifestPath)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$manifest = json_decode(file_get_contents($manifestPath), true);
|
||||||
|
|
||||||
|
if (isset($manifest[$entryName]['file'])) {
|
||||||
|
$manifestFile = $manifest[$entryName]['file'];
|
||||||
|
$fullPath = dirname($jsDir) . '/' . $manifestFile;
|
||||||
|
|
||||||
|
if (!file_exists($fullPath)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathinfo($manifestFile, PATHINFO_FILENAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
public static function tableName(string $table): string {
|
public static function tableName(string $table): string {
|
||||||
return self::APP_ID . '_' . $table;
|
return self::APP_ID . '_' . $table;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Your Name <your@email.com>
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
|
|
||||||
namespace OCA\NextcloudAppTemplate\Controller;
|
namespace OCA\NextcloudAppTemplate\Controller;
|
||||||
|
|
||||||
use OCA\NextcloudAppTemplate\AppInfo\Application;
|
use OCA\NextcloudAppTemplate\AppInfo\Application;
|
||||||
@@ -21,7 +18,6 @@ class PageController extends Controller {
|
|||||||
IRequest $request,
|
IRequest $request,
|
||||||
private LoggerInterface $logger,
|
private LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
$this->logger->info('NextcloudAppTemplate page controller loaded');
|
|
||||||
parent::__construct($appName, $request);
|
parent::__construct($appName, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,9 +31,9 @@ class PageController extends Controller {
|
|||||||
#[NoAdminRequired]
|
#[NoAdminRequired]
|
||||||
#[NoCSRFRequired]
|
#[NoCSRFRequired]
|
||||||
public function index(): TemplateResponse {
|
public function index(): TemplateResponse {
|
||||||
$this->logger->info('Forum main page loaded');
|
|
||||||
return new TemplateResponse(Application::APP_ID, 'app', [
|
return new TemplateResponse(Application::APP_ID, 'app', [
|
||||||
'script' => 'app',
|
'script' => Application::getViteEntryScript('app.ts'),
|
||||||
|
'style' => Application::getViteEntryScript('style.css'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use OCP\AppFramework\Http\TemplateResponse;
|
|||||||
use OCP\IAppConfig;
|
use OCP\IAppConfig;
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
use OCP\Settings\ISettings;
|
use OCP\Settings\ISettings;
|
||||||
use OCP\Util;
|
|
||||||
|
|
||||||
class Admin implements ISettings {
|
class Admin implements ISettings {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -27,9 +26,10 @@ class Admin implements ISettings {
|
|||||||
* @return TemplateResponse
|
* @return TemplateResponse
|
||||||
*/
|
*/
|
||||||
public function getForm(): TemplateResponse {
|
public function getForm(): TemplateResponse {
|
||||||
Util::addScript(Application::APP_ID, Application::JS_DIR . '/nextcloudapptemplate-settings');
|
return new TemplateResponse(Application::APP_ID, 'settings', [
|
||||||
Util::addStyle(Application::APP_ID, Application::CSS_DIR . '/nextcloudapptemplate-style');
|
'script' => Application::getViteEntryScript('settings.ts'),
|
||||||
return new TemplateResponse(Application::APP_ID, 'settings', [], '');
|
'style' => Application::getViteEntryScript('style.css'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSection(): string {
|
public function getSection(): string {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ use OCP\Util;
|
|||||||
|
|
||||||
/* @var array $_ */
|
/* @var array $_ */
|
||||||
$script = $_['script'];
|
$script = $_['script'];
|
||||||
Util::addScript(Application::APP_ID, Application::JS_DIR . "/nextcloudapptemplate-$script");
|
$style = $_['style'];
|
||||||
Util::addStyle(Application::APP_ID, Application::CSS_DIR . '/nextcloudapptemplate-style');
|
Util::addScript(Application::APP_ID, Application::JS_DIR . "/$script");
|
||||||
|
Util::addStyle(Application::APP_ID, Application::CSS_DIR . "/$style");
|
||||||
?>
|
?>
|
||||||
<div id="nextcloudapptemplate-app"></div>
|
<div id="nextcloudapptemplate-app"></div>
|
||||||
|
|||||||
@@ -1 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use OCA\NextcloudAppTemplate\AppInfo\Application;
|
||||||
|
use OCP\Util;
|
||||||
|
|
||||||
|
/* @var array $_ */
|
||||||
|
$script = $_['script'];
|
||||||
|
$style = $_['style'];
|
||||||
|
Util::addScript(Application::APP_ID, Application::JS_DIR . "/$script");
|
||||||
|
Util::addStyle(Application::APP_ID, Application::CSS_DIR . "/$style");
|
||||||
|
?>
|
||||||
<div id="nextcloudapptemplate-settings"></div>
|
<div id="nextcloudapptemplate-settings"></div>
|
||||||
|
|||||||
@@ -1,5 +1,33 @@
|
|||||||
import { createAppConfig } from '@nextcloud/vite-config'
|
import { createAppConfig } from '@nextcloud/vite-config'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
|
|
||||||
|
const manualChunksList = [
|
||||||
|
'emoji-mart-vue-fast',
|
||||||
|
'date-fns',
|
||||||
|
'lodash',
|
||||||
|
'floating-vue',
|
||||||
|
'vue-material-design-icons',
|
||||||
|
]
|
||||||
|
|
||||||
|
const manualChunksGroups = {
|
||||||
|
vue: ['vue-router', 'vue'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextcloudSharedList = [
|
||||||
|
'auth',
|
||||||
|
'axios',
|
||||||
|
'browser-storage',
|
||||||
|
'capabilities',
|
||||||
|
'event-bus',
|
||||||
|
'files',
|
||||||
|
'initial-state',
|
||||||
|
'l10n',
|
||||||
|
'logger',
|
||||||
|
'paths',
|
||||||
|
'router',
|
||||||
|
'sharing',
|
||||||
|
]
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default createAppConfig(
|
export default createAppConfig(
|
||||||
@@ -16,51 +44,58 @@ export default createAppConfig(
|
|||||||
'@': path.resolve(__dirname, 'src'),
|
'@': path.resolve(__dirname, 'src'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
|
visualizer({
|
||||||
|
open: process.env.VITE_BUILD_ANALYZE === 'true',
|
||||||
|
filename: 'stats.html',
|
||||||
|
template: 'treemap',
|
||||||
|
}),
|
||||||
|
],
|
||||||
build: {
|
build: {
|
||||||
outDir: '../dist',
|
outDir: '../dist',
|
||||||
|
manifest: true,
|
||||||
cssCodeSplit: false,
|
cssCodeSplit: false,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
|
entryFileNames: 'js/[name]-[hash].mjs',
|
||||||
|
chunkFileNames: 'js/[name]-[hash].mjs',
|
||||||
|
assetFileNames: '[ext]/[name]-[hash].[ext]',
|
||||||
manualChunks(id) {
|
manualChunks(id) {
|
||||||
if (id.includes('node_modules')) {
|
if (!id.includes('node_modules')) {
|
||||||
const manualChunks = [
|
return
|
||||||
'date-fns',
|
}
|
||||||
'lodash',
|
|
||||||
'dompurify',
|
// Parse package path
|
||||||
'linkifyjs',
|
|
||||||
'floating-vue',
|
|
||||||
'focus-trap',
|
|
||||||
'floating-ui',
|
|
||||||
'vue-router',
|
|
||||||
'vue-material-design-icons',
|
|
||||||
'vue',
|
|
||||||
'axios',
|
|
||||||
]
|
|
||||||
// Get the part after the last 'node_modules/' to handle pnpm structure
|
|
||||||
const parts = id.split('node_modules/')
|
const parts = id.split('node_modules/')
|
||||||
const pkgPath = parts[parts.length - 1]
|
const pkgPath = parts[parts.length - 1]
|
||||||
|
|
||||||
// Match @nextcloud/xxx packages
|
// Check for @nextcloud/xxx or nextcloud-xxx
|
||||||
const scopedNextcloudMatch = pkgPath.match(/^@nextcloud\/([^/]+)/)
|
const ncMatch = pkgPath.match(/^@?nextcloud[/-]([^/]+)/)
|
||||||
if (scopedNextcloudMatch) {
|
|
||||||
return `nextcloud-${scopedNextcloudMatch[1]}`
|
// Get the package name (e.g., 'auth', 'vue', 'axios')
|
||||||
|
const ncPkgName = ncMatch?.[1]
|
||||||
|
|
||||||
|
if (ncPkgName) {
|
||||||
|
if (nextcloudSharedList.includes(ncPkgName)) {
|
||||||
|
return 'nextcloud-common'
|
||||||
|
}
|
||||||
|
return `nextcloud-${ncPkgName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match nextcloud-xxx packages (without @ scope)
|
for (const chunk of manualChunksList) {
|
||||||
const nextcloudMatch = pkgPath.match(/^nextcloud-([^/]+)/)
|
|
||||||
if (nextcloudMatch) {
|
|
||||||
return `nextcloud-${nextcloudMatch[1]}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle other common packages
|
|
||||||
for (const chunk of manualChunks) {
|
|
||||||
if (pkgPath.includes(chunk)) {
|
if (pkgPath.includes(chunk)) {
|
||||||
return chunk
|
return chunk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'vendor' // fallback for other deps
|
for (const [groupName, groupPackages] of Object.entries(manualChunksGroups)) {
|
||||||
|
if (groupPackages.some((pkg) => pkgPath.includes(pkg))) {
|
||||||
|
return groupName
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
return 'vendor'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user