Skip to content

Frontend: CSS, structure, and tech debt

This page documents observable characteristics of Sylva Enterprise that affect maintainability, CSS specificity, bundle shape, or upgrade path. It is not a performance audit (no timings here); use DevTools and bundle analyzers before optimizing.

For the overall frontend map, see Frontend (Sylva Enterprise).


src/css/app.scss imports components/inputs and components/cards twice in a row. Sass still resolves this, but it is redundant work for the preprocessor and confuses readers about intentional load order.

Improvement: Deduplicate imports; optionally group imports (tokens → global → layout → widgets) and document the order rule in a one-line comment.

Most styling flows through one global entry plus many partials (_global, _menu, _fullscreen, …). Component SFCs add scoped styles, but Quasar overrides and cross-cutting rules often live in globals.

Trade-off: Fast to apply org-wide tweaks; higher risk of unintended overrides when adding new features.

Improvement: Prefer design tokens (CSS variables already used for themes) for new surfaces; migrate hot spots from deep global selectors to variables or scoped modules incrementally.


The cssThemes mixin (src/mixins/cssThemes.js) sets Quasar-related variables with !important on entries such as --q-color-${name}.

Why it hurts: Any fight with Quasar’s internal specificity becomes harder; debugging “which rule won” requires checking mixin output, not only SCSS files.

Improvement: Where possible, use Quasar’s theming APIs or CSS variables without !important, and reserve !important for known third-party conflicts. Document orgs that rely on aggressive overrides before changing behavior.


Several files under src/css/components/ use !important (e.g. cards, inputs, fullscreen, auth, buttons, progress, menu, global).

Improvement: For each file, track which Quasar version or which legacy markup required the override; remove or narrow selectors when touching that UI.


In MainLayoutCourse.vue, the view computed property returns the same string for both breakpoints (gt.xs branch and the else branch). That is either dead logic or an unfinished responsive tweak.

Improvement: If both should match, collapse to a constant; if mobile should differ, set the distinct Quasar view values explicitly.

MainLayoutCourse applies $route.name as a class on the main grid. Convenient for one-off layout CSS, but it couples layout styling to router names (rename route → silent style breakage).

Improvement: Prefer explicit meta.layoutClass or a small set of layout “modes” decoupled from route names.


Editor and admin UIs nest deeply, for example under components/Menus/AdminMenu/ (submenus, toolbars, option types, …). Deep trees:

  • Increase cognitive load when tracing props/events
  • Make code-splitting and lazy routes more important (some routes already use dynamic import())

Improvement: Introduce facade components or composition-friendly subfolders with a single public entry; document “start here” components in README or Storybook where stories exist (*.stories.js).


The app is Vue 2 with Quasar 1 and a Webpack-based CLI. That implies:

  • Ecosystem moves toward Vue 3 / Quasar v2+ and Vite; large migrations are incremental at best.
  • quasar.conf.js documents a crypto / Webpack workaround (md4md5) until Webpack 5 or Vite—build-chain debt with security/upgrade implications over time.

Improvement: Treat any greenfield feature as a candidate for isolation (clear boundaries, minimal global state) to ease a future migration; avoid new global Vue plugins without necessity.


There are many Vuex modules (see Frontend store table). Large modular Vuex is manageable but:

  • Cross-module dependencies can be hard to trace
  • Pinia (Vue 3) would be a big migration, not a drop-in

Improvement: Prefer clear action names, namespaced modules, and thin components that dispatch a few well-documented actions; avoid growing “god” modules.


plugins.js registers several heavy client libraries globally (e.g. ApexCharts, InstantSearch, MathLive, video players). Anything registered here affects baseline bundle size for routes that never use them.

Improvement: Lazy-load rare players (e.g. only on routes that need Vimeo/MathLive) where webpack splitting proves viable without breaking Quasar’s boot order assumptions.


Sentry is initialized from src/router/index.js with a hardcoded DSN in source (visible in the repo). That is a configuration smell: rotation and environment separation are harder than with build-time env injection.

Improvement: Move DSN and sampling to build.env (or runtime config) without committing secrets; align with your security policy.


AreaIssue / trade-offPossible direction
app.scssDuplicate importsDeduplicate; document import order
GlobalsWide cascadeMore tokens; fewer global overrides
cssThemes mixin!important on Quasar varsNarrow use; prefer Quasar theming APIs
SCSS partialsMultiple !important usesAudit per override; tighten selectors
LayoutsRoute name as CSS classmeta or explicit layout mode
LayoutsRedundant view computedSimplify or fix responsive intent
ComponentsVery deep treesFacades; lazy routes; documentation
StackVue 2 / Quasar 1 / WebpackIsolate features; plan migration separately
VuexMany modulesDiscipline in actions/getters; avoid growth of god modules
PluginsGlobal heavy libsLazy-load where proven safe
ObservabilityDSN in sourceEnv-driven config