nasirkhan/laravel-jodit
Laravel Jodit integrates the Jodit WYSIWYG editor through one reusable Blade component, working in plain Blade templates, view components, and Livewire. Includes a bundled file browser and uploader, CDN assets, and a publishable config.
Architecture fit. nasirkhan/laravel-jodit is a thin presentation-layer wrapper, not a content platform. The architecture is a Blade anonymous component that renders a <textarea> plus Jodit initialisation JS, backed by an optional connector controller for file browse/upload. It is framework-native (service provider auto-discovery, publishable config, asset stacks, route registration) and imposes no persistence model, no migrations, no content schema, and no opinion on how HTML is stored or sanitised. That is the right shape for a package in this class: it slots into existing form request → validation → Eloquent save flows without touching them. It is a poor fit only where the frontend is not Blade-rendered (Inertia/Vue/React SPA surfaces), since the integration vector is a server-rendered component and Livewire's wire-model.
Integration feasibility. High for a standard Laravel 11/12/13 monolith on PHP 8.2+. The surface area is one component tag, two optional props (wire-model, connector-url), and a config file. The Livewire path is handled explicitly — the wrapper is set to wire:ignore to survive DOM diffing, with a 300 ms debounced JS flush back to the component. Two prerequisite couplings to validate up front: the layout must emit @stack('after-styles') and @stack('after-scripts') (or these must be renamed in config), and the connector route is registered by default with ['web', 'auth'] middleware. Both are cheap to confirm in a spike but are silent-failure modes if missed — no stack means no assets and no editor, with no error surfaced.
Technical risk. The dominant risks are not in the Blade wiring; they are in the connector and the asset delivery path.
svg in allowed_mimes against the public disk, with max_file_size at 10 MB. SVG is an active-content format and a well-known stored-XSS vector when served same-origin from a public path. There is no documented per-user or per-tenant path isolation, no documented re-encoding pass on images, no malware scanning, and no documented base_path traversal hardening. Route::any on the connector is broader than the protocol requires and ships without throttling by default. Treat the built-in connector as a convenience, not a hardened upload surface.script-src/style-src allowlisting, supply-chain trust in the pin, and offline/air-gapped infeasibility. No Subresource Integrity is documented. Mitigation is to self-host the two URLs via config, which is supported but must be an explicit decision, not a default.intervention/image ^4.0. A substantive transitive dependency pulled in solely for resize/crop. It brings GD/Imagick build requirements into the container image and a major-version upgrade obligation. If the team already standardises on a different image pipeline, this is duplicated capability.wire:ignore means there is a real window where editor content is not yet in the Livewire property. A submit or navigation inside the debounce interval can persist stale content. Verify the component's flush-on-submit behaviour before trusting it in high-stakes forms; a plain Blade submit with the underlying textarea is materially safer.v2.0.0 release notes describe only README and error-message changes — a major version bump for documentation signals loose semver discipline, which means "minor" releases are not reliably non-breaking. Bus factor is 1.Key questions.
script-src policy and SRI in place?wire:model-adjacent hidden field fallback?intervention/image v4 already in our dependency tree, or are we accepting a new image-processing contract for resize/crop alone?Stack fit. Best fit: Laravel monolith, Blade-first views, Livewire for interactive forms, standard session auth. Acceptable fit: Blade-only apps with no Livewire (use the plain :value path). Poor fit: API-only services, Inertia/SPA frontends, or multi-guard/multi-tenant apps where the default auth middleware on the connector resolves to the wrong guard — that must be overridden regardless.
Migration path. Content is portable in both directions. Jodit emits HTML into a textarea, so migrating from TinyMCE, CKEditor 4/5, Summernote, or Trumbowyg is a swap of the editor shell around the same stored field; no content rewrite is required in the common case, though editor-specific artefacts (custom embeds, shortcodes, inline style conventions) will render differently and need a sampling audit. Migrating away later is equally low-cost, which is the main argument for accepting the maturity risk: the blast radius of replacement is one component and one config file. The non-portable surface is uploaded media — those live on whatever disk base_path points to, so plan a storage layout and a URL strategy that survives a future editor swap (stable, non-Jodit-specific paths).
Compatibility. Confirm three things before committing: PHP 8.2+ and Laravel 11/12/13 in the target app; the layout's asset stacks match after-styles/after-scripts or the config is overridden; and the container can satisfy intervention/image v4 (GD or Imagick extension, memory limits adequate for image resize during request handling). Watch the semver signal — pin to an exact version in composer.json rather than floating a caret range, and review each upstream release diff rather than trusting the version number.
Sequencing.
wire-model sync and the submit-race behaviour.route.enabled => false), register JoditConnectorController behind the admin prefix with explicit middleware, add throttling, move to a private/non-web-root disk with a signed-URL or controller-served read path, drop svg from allowed_mimes unless there is a documented need and a serving strategy that neutralises it, and reduce max_file_size to the actual product requirement.Maintenance. Low steady-state effort, with two recurring obligations. First, Jodit version currency: the editor version is a config string, which makes upgrades trivial but also easy to leave stale — schedule a periodic review of the pinned version and upstream CVEs. Second, composer constraint hygiene: given the imprecise semver observed, exact-pin and review release diffs. The consuming team owns everything the package deliberately does not provide — sanitisation, upload hardening, storage lifecycle and retention, and any cleanup of orphaned media when content is deleted. Assume no upstream support SLA.
Support. Effectively none. Single maintainer, 2 stars, 0 dependents, README-only documentation, no community channel of consequence. Escalation path is reading the source and forking under MIT. That is acceptable for a small, self-contained Blade component — the code volume is small enough to own — but it must be a conscious acceptance, not a surprise. Name an internal owner.
Scaling. The editor itself is client-side and scales trivially. The connector does not: uploads and any resize/crop work execute synchronously inside the PHP request cycle, so large images or concurrent uploads translate directly into worker occupancy and memory pressure. There is no queueing, no async processing, and no CDN offload documented. Mitigations in order of preference: cap max_file_size tightly, raise proxy client_max_body_size in step with it (a mismatch here produces opaque 413s), offload reads to a CDN or object store, and move image transcoding out of the request path if upload volume is material. Multi-tenant deployments should treat media isolation as an app-level concern the package does not solve.
Failure modes. Ranked by likelihood and blast radius:
upload_max_filesize, and package max_file_size produce failures that read as generic editor errors. Align the three and surface the real message.public symlink not created: uploads appear to succeed or fail inconsistently; media links break after content is saved.Ramp-up. Developer ramp-up is genuinely small — one tag, one config file, a documented prop table and button reference. An engineer unfamiliar with the package is productive in under a day. The real ramp-up cost sits with security and platform review, not with the developers: the connector hardening, sanitiser selection, asset-hosting decision, and CSP change each require a reviewer who understands the exposure. Budget that review as part of adoption rather than discovering it at launch. Overall verdict: a reasonable, low-coupling choice for trusted-author content in a Blade/Livewire Laravel app, on the explicit condition that the upload and sanitisation surfaces are hardened by the consuming team and a single internal owner is named.
How can I help you explore Laravel packages today?