marshmallow/nova-tinymce
A TinyMCE rich-text editor field for Laravel Nova, adding a WYSIWYG input to Nova forms so you can create and format content with familiar TinyMCE editing tools.
Architecture fit. The package is a thin Nova field wrapper: a PHP Field subclass plus a compiled Vue component that mounts TinyMCE over a textarea and exposes an image-upload endpoint. It fits cleanly into the standard Nova extension pattern (asset registration in a package service provider via Nova::script/Nova::style), so it does not alter application architecture. The real architectural weight sits behind the wrapper: TinyMCE is a large client-side dependency, and image upload introduces a write path (auth, validation, storage disk, public URL generation) that did not previously exist for that field. Treat the field as "TinyMCE + a file-upload surface," not as a cosmetic editor swap. v2.3.2 reinforces that the asset-registration contract is itself part of the architecture: Nova resolves registered assets by case-sensitive name at a URL path, so the package's asset names are coupled to host/CDN/proxy URL-normalization behavior, not just to Nova's version.
Integration feasibility. Low effort to install (composer require, publish config/assets, add TinyMCE::make('body') to a Nova resource), but only if the target app already runs Nova. Nova is a paid, closed-source first-party product, so the package is unusable outside a licensed Nova installation, and viability is gated on Nova version compatibility rather than Laravel compatibility alone. The 3-star / 0-dependent profile means there is effectively no public validation of the integration path: no downstream projects exercising upgrades, no issue history proving it survives Nova majors. The v2.3.2 changelog is a concrete illustration of the gap — a total, site-wide save outage on one host configuration that persisted a week and was found by a single adopter, not by any downstream test surface. Budget a spike to confirm the field renders, persists, and uploads on the exact Nova/PHP/Laravel versions in use, and on the exact host/proxy configuration in use.
Technical risk. Ranked by exposure:
valid_elements/paste policy, this becomes a stored-XSS vector, especially for lower-trust admin roles.TypeError: t.fill is not a function without sending a request. The failure is silent server-side — nothing in the logs — and blocks all saves on affected resources, including no-op saves. This is a class of risk, not a one-off: any middleware, CDN, or SEO layer that rewrites path case can sever the field from its assets. Confirm our edge/proxy chain does not normalize case and that the upgrade to 2.3.2 (or our fork pin) actually lands the lowercase names.Key questions. Which Nova major and Laravel/PHP versions are in scope, and is the package's composer constraint actually satisfied? Does our host, CDN, or middleware chain normalize URL casing (SEO redirects, path canonicalization), and would a capitalised asset path survive it? Is TinyMCE to be self-hosted (asset-published) or loaded from Tiny Cloud/CDN, and does that pass our CSP? Where do uploaded images live — public disk, S3, per-tenant prefix — and who authorizes the upload route? What sanitization runs server-side on save, and is it in the package or must we add it? Do we capture browser-side JS errors in the admin panel, and do we have a synthetic check that actually submits a Nova form using this field? Do we accept owning a fork, and who is the named owner? Is the built-in Nova Trix field, or a maintained CKEditor/TinyMCE field, sufficient for the same use case?
Stack fit. Assumes Laravel + Nova with the standard Composer/asset-publish workflow. The package adds one field type and one upload route; it does not touch the domain model beyond the existing text column. That is a good fit for CMS-style resources (pages, posts, product descriptions) and a poor fit for anything requiring structured content, because free-form HTML in a single column is hard to query, validate, and migrate later. If the content is customer-facing, plan for a rendering/sanitization layer downstream of storage.
Migration path. Start by pinning the package to an exact version in a fork we control (or vendor it under our namespace). v2.3.2 is a drop-in patch — only the three registered asset names change; the Vue component names and TinyMCE.php's $component are a separate contract with the built dist/ bundle and are untouched — so the upgrade itself carries low risk and we should take it immediately as the fork baseline rather than shipping 2.3.1. Add a server-side sanitizer on the model (observer/mutator) so protection does not depend on the editor. Then adopt the field in one low-risk Nova resource — internal notes or an admin-only description — and only expand to public-facing content after the sanitizer and upload hardening are proven. For content already in plain textareas, migration is non-destructive (the column type is unchanged); the practical migration is a one-time normalization pass to clean legacy HTML and strip disallowed tags before enabling the editor broadly.
Compatibility. Verify four axes independently now, not three: Nova major (field asset API and Vue version), Laravel/PHP (service provider and upload route conventions), TinyMCE major (config option names have shifted across v6/v7), and host/edge URL handling (case sensitivity of the asset paths Nova serves). The fourth axis is the one that broke a production site for a week while composer.json ranges, Nova version, and Laravel version were all fine. Because the package has no dependent projects, assume the compatibility matrix is unverified and test each axis explicitly rather than trusting composer.json ranges. Keep a fallback: the package is small enough that reimplementing the field in-house against TinyMCE's documented API is a realistic two-to-five-day task and removes the third-party dependency entirely — and would let us own the asset-naming contract directly.
Sequencing.
Maintenance. This is the dominant cost. With 3 stars, 0 dependents, and no visible downstream usage, assume no upstream support and budget for an internally owned fork. Realistically that means a few hours per quarter plus a half-day whenever Nova major-upgrades, TinyMCE majors, or the CDN/asset pipeline changes. v2.3.2 adds a specific, recurring maintenance item: re-verify asset name registration after any change to hosting, CDN, or SEO/redirect middleware, since that is now a demonstrated break vector. Track it in the same inventory as other admin-panel dependencies so an upgrade doesn't silently break rich-text editing.
Support. No community to escalate to; issues may go unanswered. First-line support should be the internal owner, with a documented fallback (disable the field, revert to textarea/Trix) so an editor outage is a degraded experience, not an admin lockout. Document the TinyMCE config surface — toolbar and paste behavior will generate the most user questions. v2.3.2 adds a harder support requirement: the worst failure mode is invisible to server-side logs, so the support runbook must explicitly include "check the browser console" as step one for any "save does nothing" report, and the triage script must distinguish a client-side component-registration failure from a validation or authorization rejection. Without that, an on-call engineer sees a clean server log and has no leads — exactly the week-long outage described upstream.
Scaling. Editor work is client-side and scales with the admin session, not with traffic, so it is not a throughput concern. The scaling costs are storage and payload: images accumulate, so a CDN/public disk plus lifecycle cleanup for orphans is needed; HTML bodies inflate row size, so confirm LONGTEXT and request-size limits for large pastes (base64 images pasted inline are a common surprise). If many editors work concurrently, the upload endpoint becomes a modest write path — validate and rate-limit it like any public upload.
Failure modes.
mix manifest mismatch) → textarea renders unusable.TypeError: t.fill is not a function, no request is sent, and nothing appears in server logs. Fix is in 2.3.2; the residual risk is any future asset rename or re-registration reintroducing a case mismatch, or our fork pin drifting back to 2.3.1.Ramp-up. Developer ramp-up is low: a Nova-familiar engineer can wire the field in under an hour, and forking/reimplementing is a few days. Ops and security ramp-up is moderate: CSP changes, storage/disk policy, upload validation, and sanitization review each need a reviewer who understands the admin panel's threat model. Add one deliberately unglamorous item — browser-side error capture for the admin panel plus a synthetic canary that loads a Nova form with this field and submits it — because v2.3.2 proved this package can be totally non-functional while every server-side signal stays green. Editor users need a short style-guide note on paste behavior and image sizing. Net TPM recommendation: acceptable as a small, contained capability in an already-licensed Nova admin, contingent on pinning at v2.3.2, forking, sanitizing server-side, hardening uploads, verifying URL-case handling end to end, and adding a client-side smoke test — treat the package as a starting point we own, not a supported dependency.
How can I help you explore Laravel packages today?