mirror of
https://github.com/wekan/wekan.git
synced 2026-11-06 12:45:03 -05:00
295 lines
14 KiB
Markdown
295 lines
14 KiB
Markdown
# Less Code
|
|
|
|
This document records a measured plan for reducing WeKan's maintained source
|
|
code without removing supported behaviour, translations, accessibility or
|
|
tests. Fewer lines are useful only when they also leave fewer independent
|
|
implementations to understand and keep consistent.
|
|
|
|
## Baseline
|
|
|
|
Measured on 2026-09-03 from JavaScript, Jade, CSS and MJS files below
|
|
`client/`, `server/`, `imports/` and `models/`:
|
|
|
|
| Source | Files | Lines |
|
|
| --- | ---: | ---: |
|
|
| JavaScript and MJS | 798 | 150,724 |
|
|
| CSS | 73 | 28,941 |
|
|
| Jade | 111 | 13,287 |
|
|
| Total | 982 | 192,952 |
|
|
|
|
Generated bundles, dependencies, translation JSON and tests are not included.
|
|
The baseline is a navigation aid rather than a target to game: moving code to
|
|
generated files or compressing formatting does not count as a reduction.
|
|
|
|
The largest promising areas found in the initial survey are:
|
|
|
|
| Area | Current evidence | Opportunity |
|
|
| --- | --- | --- |
|
|
| Board themes | `boardColors.css` is 6,339 lines | Store theme values once and share structural rules |
|
|
| Language registry | `languages.js` is 1,724 lines | Generate repetitive registry entries from compact metadata |
|
|
| Large UI controllers | Several files have 1,400-2,900 lines | Extract genuinely repeated paging, forms and actions |
|
|
| Authorization | Rules occur in models, methods, publications and REST routes | Use one policy function per operation |
|
|
| Importers | Creator modules repeat entity creation pipelines | Normalize input, then persist through one pipeline |
|
|
| Retired paths | Dynamic Blaze references hide some unused code | Remove only with runtime and test evidence |
|
|
|
|
Splitting a large file, changing Jade to Svelte, minifying source, or moving
|
|
logic into a dependency does not by itself satisfy this plan.
|
|
|
|
## Working rules
|
|
|
|
Each phase is completed and verified before the next begins. Record its before
|
|
and after measurements below. Behavioural changes need positive and negative
|
|
tests; visible changes also need an applicable UI or screenshot test. Preserve
|
|
special cases instead of forcing them into an abstraction that makes the code
|
|
harder to understand.
|
|
|
|
Small migrations are preferred. A phase may be stopped when measurement shows
|
|
that its abstraction adds more complexity than it removes.
|
|
|
|
## Phase 1: board theme declarations
|
|
|
|
`client/components/boards/boardColors.css` repeats selectors and declarations
|
|
for every named theme. Introduce shared structural rules backed by CSS custom
|
|
properties, while retaining explicit overrides for gradients, image themes,
|
|
Apple Glass Pastel and other exceptional designs.
|
|
|
|
Steps:
|
|
|
|
1. Inventory the property roles used by ordinary colour themes and classify
|
|
exceptional themes.
|
|
2. Add a shared rule set and a small variable declaration for one ordinary
|
|
theme.
|
|
3. Extend the existing theme tests so they verify computed outcomes rather
|
|
than requiring the old repeated selector layout.
|
|
4. Migrate ordinary themes in small batches and run the theme, header, public
|
|
board, All Boards and checkbox tests after each batch.
|
|
5. Compare CSS size and a representative rendered board in desktop and mobile
|
|
widths. Keep special-theme CSS explicit where that is clearer.
|
|
|
|
Acceptance criteria:
|
|
|
|
- all existing visual behaviours and theme choices remain available;
|
|
- theme tests and relevant Playwright tests pass;
|
|
- `boardColors.css` has materially fewer declarations and bytes;
|
|
- a new ordinary solid-colour theme can be added mainly by declaring values.
|
|
|
|
Result:
|
|
|
|
- ten ordinary solid-colour themes now declare twelve palette values and use
|
|
one shared structural rule set;
|
|
- gradient, image, Relax, Dark, Apple Glass Pastel, Modern and Clean themes
|
|
remain explicit because their structure or behaviour differs;
|
|
- `boardColors.css` decreased from 6,339 lines / 196,012 bytes / 1,266 rules /
|
|
2,216 declarations to 5,895 lines / 178,134 bytes / 1,058 rules / 2,064
|
|
declarations;
|
|
- PostCSS parsed the resulting stylesheet successfully;
|
|
- `themeAccents`, `boardTileTheme`, `allBoardsPage`, `publicBoardsPage`,
|
|
`headerBars`, `checkboxesAreSquare` and `appleGlassPastelTheme` passed: 110
|
|
assertions in total;
|
|
- a Chromium computed-style check was attempted at 1,280 px and 390 px, but
|
|
this ARM64 sandbox only has an x86-64 Chromium binary and its emulated launch
|
|
did not complete. Runtime visual verification therefore remains an
|
|
environment boundary rather than a claimed result.
|
|
|
|
Status: **completed** in commit `cd1039230`.
|
|
|
|
## Phase 2: language metadata
|
|
|
|
Replace repetitive hand-written language registry objects with compact
|
|
metadata and generated lazy imports. The public registry shape and language
|
|
order must remain unchanged. Adding a language must still require all three
|
|
integration points specified by the translation policy.
|
|
|
|
Acceptance criteria:
|
|
|
|
- every current locale is registered with the same code, tag, native name and
|
|
RTL value;
|
|
- every translation remains lazily loaded;
|
|
- translation, key-order, placeholder and language-picker tests pass;
|
|
- the authoritative metadata is shorter and has a duplicate-tag check.
|
|
|
|
Result:
|
|
|
|
- the 245 language records now use one compact metadata row each;
|
|
- a separate loader map retains one literal dynamic `import()` per language,
|
|
preserving Meteor's per-language split points;
|
|
- a runtime parity comparison against the previous module confirmed identical
|
|
keys, codes, tags, native names, RTL flags and loader paths for all 245
|
|
entries;
|
|
- `languages.js` decreased from 1,724 lines / 34,873 bytes to 510 lines /
|
|
24,362 bytes;
|
|
- guards now reject duplicate metadata keys, duplicate language tags, duplicate
|
|
loader keys, missing loaders, eager imports and files not claimed by the
|
|
registry;
|
|
- `i18nLazyLoading`, `i18nLazyLoaded`, `newLanguageWiring`, `rtl` and
|
|
`changeLanguageColumns` passed: 31 assertions in total.
|
|
|
|
Status: **completed** in commit `a3bc8155d`.
|
|
|
|
## Phase 3: repeated UI mechanics
|
|
|
|
Measure duplication in large UI files before extracting anything. Concentrate
|
|
on repeated pagination, searches, menu data, modal lifecycle, form value
|
|
collection and Meteor method result handling. Do not create generic helpers for
|
|
code that merely looks similar but has different behaviour.
|
|
|
|
Acceptance criteria:
|
|
|
|
- at least two real consumers use every extracted abstraction;
|
|
- user-visible error, keyboard and accessibility behaviour is preserved;
|
|
- focused unit tests cover the shared primitive and UI tests cover consumers;
|
|
- total maintained code is lower after including the new abstraction.
|
|
|
|
Result:
|
|
|
|
- one `adjacentPage` primitive now clamps page movement for All Boards, the
|
|
generic Admin Panel reports, event streams, office reports and all four
|
|
People paging contexts;
|
|
- People maps the active pane to its page, total and page-size state once,
|
|
replacing separate previous/next branches for organizations, teams, people
|
|
and the login-location drill-down;
|
|
- focused tests cover ordinary movement, both boundaries, normalized direction
|
|
and invalid movement; the existing consumer suites passed with 96 assertions
|
|
(`tablePage` 55, `allBoardsPage` 27, subscription lifetime 3 and grouped
|
|
offices 11);
|
|
- the 982-file maintained-source measurement decreased from 191,284 to 191,279
|
|
lines. The small five-line net reduction includes the new shared primitive;
|
|
tests are excluded from that measurement and grew to pin its behaviour.
|
|
|
|
Status: **completed** in commit `eb0e34786`.
|
|
|
|
## Phase 4: authorization policies
|
|
|
|
Inventory equivalent permission decisions across collection methods, Meteor
|
|
methods, publications and REST endpoints. Move each equivalent decision into a
|
|
pure shared policy and retain transport-specific error formatting at the edge.
|
|
|
|
Acceptance criteria:
|
|
|
|
- DDP and REST make the same decision for the same actor and resource;
|
|
- policies have allowed and denied tests, including missing resources;
|
|
- publications do not expose records rejected by their matching mutation
|
|
policy;
|
|
- duplicated permission conditions are removed rather than wrapped.
|
|
|
|
Result:
|
|
|
|
- the existing write-capability policy was confirmed to serve collection
|
|
permissions, Meteor methods, REST mutations and destination checks in
|
|
publications; it was retained instead of creating a competing abstraction;
|
|
- a new transport-neutral `canReadBoard` policy now serves two DDP
|
|
publications, two HTTP attachment routes and fourteen position-history
|
|
method checks;
|
|
- public boards allow anonymous and authenticated reads, private boards require
|
|
an active member, and missing or malformed boards fail closed;
|
|
- HTTP and DDP keep their own response/error formatting at their edges. The
|
|
legacy attachment publication now makes the same public-board decision as
|
|
the HTTP download routes instead of rejecting every anonymous subscriber;
|
|
- six focused policy and wiring tests passed, together with the existing file
|
|
safety, request authentication, card scope and window-publication suites;
|
|
- maintained source decreased from 191,279 to 191,248 lines, including the new
|
|
policy module.
|
|
|
|
Status: **completed** in commit `e8c867b33`.
|
|
|
|
## Phase 5: importer pipeline
|
|
|
|
Define a small internal board representation for importers. Source-specific
|
|
modules parse and normalize their data; one tested writer creates users,
|
|
boards, swimlanes, lists, cards, comments, checklists and attachments.
|
|
|
|
Acceptance criteria:
|
|
|
|
- existing supported import formats retain their behaviour;
|
|
- source-specific quirks remain visible in their adapters;
|
|
- malformed and partial imports have negative tests;
|
|
- entity creation and ID-mapping logic has one implementation where possible.
|
|
|
|
Result:
|
|
|
|
- WeKan JSON and Trello adapters now describe their ordered stages to one
|
|
`runImportPipeline` implementation, which carries the created board ID and
|
|
normalizes absent optional collections to empty arrays;
|
|
- one `writeImportedEntity` implementation now owns direct insertion, optional
|
|
timestamp touching and old-to-new ID recording for lists, swimlanes,
|
|
checklists and WeKan custom fields;
|
|
- source-specific normalization remains in the adapters: notably WeKan's real
|
|
swimlanes and extra dependency/rule stages, and Trello's synthetic default
|
|
swimlane and inline checklist items;
|
|
- malformed top-level input and a pipeline that creates no board fail closed;
|
|
missing optional arrays, stage order, ID propagation, mapping and timestamp
|
|
writes have focused positive and negative tests;
|
|
- six pipeline tests and 95 existing importer assertions passed. The three
|
|
changed modules also passed Node 24 syntax checks;
|
|
- maintained source decreased from 191,248 to 191,220 lines, including the new
|
|
pipeline module. Obsolete commented-out importer implementations and the
|
|
unused empty WeKan checker were removed as part of the same inventory.
|
|
|
|
Status: **completed** in commit `8b7115335`.
|
|
|
|
## Phase 6: evidence-based removal
|
|
|
|
Run static analysis as a candidate generator, then verify candidates against
|
|
Blaze template names, dynamic imports, global registrations, server startup
|
|
side effects and packaging entry points. Remove retired compatibility paths
|
|
and unused feature code only after that inspection.
|
|
|
|
Acceptance criteria:
|
|
|
|
- every removal has search evidence and relevant regression coverage;
|
|
- application startup, production build and registered test suites succeed;
|
|
- no supported deployment mode or documented feature is silently removed.
|
|
|
|
Result:
|
|
|
|
- static search found two tracked model implementations whose `.disabled`
|
|
suffix prevents Meteor from treating them as JavaScript. No import, template,
|
|
startup registration, package entry or application source referenced their
|
|
filenames or `AttachmentsOld` / `AvatarsOld` symbols;
|
|
- `models/attachments_old.js.disabled` and
|
|
`models/avatars_old.js.disabled` were removed: 148 tracked lines. These files
|
|
are recoverable from git history;
|
|
- supported legacy CollectionFS reads remain in
|
|
`attachmentBackwardCompatibility.js`, the legacy attachment publication and
|
|
its HTTP route. Migration extraction and file-safety suites passed;
|
|
- a regression test verifies that the retired files and symbols stay absent
|
|
while the active legacy-read modules remain present;
|
|
- all 709 registered Node test suites passed with zero failures in 48 seconds;
|
|
- `meteor build .build-lesscode --directory` completed successfully. Its only
|
|
diagnostics were existing asset-size and optional MongoDB dependency
|
|
warnings;
|
|
- a development startup with a temporary `WRITABLE_PATH` reached `Started your
|
|
app` and served at `http://127.0.0.1:3999`, after which it was stopped cleanly;
|
|
- the maintained-source metric is unchanged at 191,220 because `.disabled`
|
|
files were deliberately excluded from that baseline. The removal nevertheless
|
|
deletes 148 tracked, reviewable lines rather than moving or compressing them.
|
|
|
|
Status: **completed** in commit `e37717d07`.
|
|
|
|
## Results
|
|
|
|
| Phase | Before | After | Tests | Result |
|
|
| --- | ---: | ---: | --- | --- |
|
|
| Baseline | 192,952 lines | 191,220 lines | Not applicable | 1,732 fewer maintained lines |
|
|
| 1. Board themes | 6,339 lines / 196,012 bytes | 5,895 lines / 178,134 bytes | 110 assertions passed; browser unavailable | Completed (`cd1039230`) |
|
|
| 2. Language metadata | 1,724 lines / 34,873 bytes | 510 lines / 24,362 bytes | Registry parity and 31 assertions passed | Completed (`a3bc8155d`) |
|
|
| 3. UI mechanics | 191,284 maintained lines | 191,279 maintained lines | Primitive and 96 consumer assertions passed | Completed (`eb0e34786`) |
|
|
| 4. Authorization | 191,279 maintained lines | 191,248 maintained lines | 6 policy tests plus transport regressions passed | Completed (`e8c867b33`) |
|
|
| 5. Importers | 191,248 maintained lines | 191,220 maintained lines | 6 pipeline and 95 importer assertions passed | Completed (`8b7115335`) |
|
|
| 6. Removal | 148 tracked disabled lines | 0 tracked disabled lines | 709 Node suites, build and startup passed | Completed (`e37717d07`) |
|
|
|
|
## Final outcome
|
|
|
|
All six phases are complete. The maintained JavaScript/MJS, Jade and CSS metric
|
|
decreased from 192,952 to 191,220 lines: **1,732 fewer maintained lines**. Phase
|
|
6 additionally removed 148 tracked disabled lines that were outside the
|
|
baseline, for **1,880 deleted or avoided lines** across the measured work.
|
|
|
|
The reductions came from fewer independent implementations, not from
|
|
minification or changing template technology. Replacing all Jade/Blaze views
|
|
with Svelte would temporarily increase code because both UI systems, adapters
|
|
and migration tests would coexist; it is therefore not a code-reduction step by
|
|
itself. Further work should repeat this measured approach on one duplicated
|
|
behavior at a time and retain a change only when its tests and maintenance
|
|
surface improve.
|