Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Moment Js Bundle Laravel Package

stinger/moment-js-bundle

A Laravel bundle that packages Moment.js for easy asset publishing and Blade-ready usage. It simplifies including the library in your views without relying on external CDNs, with configurable paths for a cleaner, self-hosted frontend setup.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the reality check: stinger/moment-js-bundle is a Symfony2 bundle, not a Laravel package. It is a thin wrapper that ships a pinned moment.js build inside Resources/public/js/ and wires it into Symfony's asset/Twig layer. There is no service provider, no facade, no config file that Laravel's container will ever read. On a Laravel project the bundle will install but will never "boot" — so treat it as an asset source, not a dependency.

Where to look first (in vendor/stinger/moment-js-bundle/):

Path What's there
Resources/public/js/moment*.js The actual library — this is the only file you care about
Resources/views/ Twig snippet(s) that emit the <script> tag
DependencyInjection/, StingerMomentJsBundle.php Symfony kernel wiring; irrelevant to Laravel
composer.json Pinned moment version and Symfony constraint (~2.x)

Minimal steps for a Laravel developer:

composer require stinger/moment-js-bundle
# copy the asset out — do not rely on the vendor path at runtime
cp vendor/stinger/moment-js-bundle/Resources/public/js/moment.min.js \
   resources/js/vendor/moment.js
composer remove stinger/moment-js-bundle

Then import it from your Vite entry:

// resources/js/app.js
import moment from './vendor/moment.js';
window.moment = moment;
{{-- resources/views/posts/show.blade.php --}}
<time datetime="{{ $post->published_at->toIso8601String() }}"
      data-moment="{{ $post->published_at->toIso8601String() }}">
  {{ $post->published_at->diffForHumans() }}
</time>
document.querySelectorAll('[data-moment]').forEach(el => {
  el.textContent = moment(el.dataset.moment).fromNow();
});

First real use case: localized "3 hours ago" / "2 days ago" timestamps on a Blade listing page, where Carbon renders the SSR fallback and moment upgrades it client-side.

Implementation Patterns

Pattern 1 — Vendor-asset extraction (the only sane Laravel pattern)

Composer-install once, copy the JS into resources/js/vendor/, remove the composer requirement, and commit the file. This gives you a reproducible build, no Symfony transitive dependencies, and no reliance on a 2015 package staying on Packagist. Pin the copied file's version in a comment or a vendor/manifest.json.

Pattern 2 — CDN substitution

Because the bundle is just a moment build, the honest equivalent is:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/min/moment.min.js"></script>

You get a newer, patched moment than the 2015 bundle ships, with zero install cost. The only reason to prefer the bundle's copy is offline/air-gapped builds or a hard dependency-pinning policy.

Pattern 3 — Blade component wrapper

Centralize the markup so you can swap the formatter later without touching views:

// app/View/Components/RelativeTime.php
class RelativeTime extends Component
{
    public function __construct(public \Carbon\CarbonInterface $date) {}
    public function render() { return view('components.relative-time'); }
}
{{-- resources/views/components/relative-time.blade.php --}}
<time datetime="{{ $date->toIso8601String() }}"
      data-moment="{{ $date->toIso8601String() }}">
  {{ $date->diffForHumans() }}
</time>

This makes a future migration to Day.js or Intl.RelativeTimeFormat a one-file change.

Pattern 4 — Locale handoff from Laravel

Moment's locale is client-side; Laravel's is server-side. Bridge them explicitly:

<script>
  window.__locale = @json(str_replace('_', '-', app()->getLocale()));
</script>
import 'moment/locale/fr';
import 'moment/locale/de';
moment.locale(window.__locale || 'en');

Remember: the bundle does not ship locale files or moment-timezone. You must add those yourself.

Pattern 5 — Hybrid SSR + hydration

Render a Carbon diffForHumans() on the server (correct for crawlers and no-JS), then overwrite with moment on DOMContentLoaded. Use the datetime attribute as the single source of truth — never parse the human string.

Pattern 6 — If you genuinely run Symfony alongside Laravel

Register in AppKernel::registerBundles(), run bin/console assets:install --symlink, and include the bundle's Twig snippet. This is the only scenario where the bundle's wiring adds value over copying the file.

Gotchas and Tips

The package is dead. Last release 2015-07-01, 0 stars, 0 dependents. The moment build it ships predates moment-timezone integration, most locale files, and two ReDoS advisories (CVE-2022-31129, CVE-2020-28500). If you copy the asset, immediately replace it with [email protected] or migrate to Day.js.

Moment itself is legacy. Since 2020 the maintainers put moment in maintenance mode and recommend Day.js (2 kB, moment-compatible API), Luxon, or native Intl.RelativeTimeFormat. For a Laravel app in 2024+, Day.js is a near drop-in for the patterns above:

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);

Symfony kernel coupling. composer require stinger/moment-js-bundle may pull Symfony 2.x components that conflict with Laravel's symfony/* constraints (Laravel 9+ uses Symfony 6). Composer may resolve, downgrade, or hard-fail. Always extract-and-remove rather than leaving it in require.

Assetic-era asset handling. The bundle assumes assets:install symlinks Resources/public into web/bundles/. That has no analogue in Laravel — Vite/Mix will not find files under vendor/. Copy them.

Don't call moment(string) on non-ISO input. It emits a deprecation warning and falls back to new Date(), which is browser-dependent. Always pass toIso8601String() from Laravel, which is UTC and unambiguous.

Timezone trap. Plain moment parses ISO strings with offsets correctly but format() renders in the browser's zone. If you need "display in the user's account timezone" independent of the OS, the bundle cannot help — you need moment-timezone or Luxon, both absent.

Debugging checklist when the script "isn't there":

  1. bin/console assets:install --symlink (Symfony) or npm run build (Laravel).
  2. Check the emitted <script> path — Symfony resolves to /bundles/stingermomentjs/js/moment.min.js.
  3. If moment is not defined, confirm the script tag precedes your inline usage, and that Vite didn't tree-shake the import (it won't — moment has side effects — but a bare import './vendor/moment.js' without assignment will).
  4. Verify window.moment is set if you're using inline Blade scripts.

Extension points that actually exist:

  • Symfony: override the bundle's Twig template via app/Resources/StingerMomentJsBundle/views/ (bundle inheritance) to swap in a CDN or a different build.
  • Laravel: there are none — the extension point is your own Blade component (Pattern 3). Build one, and the vendor swap stays invisible to your views.

Bottom line for a Laravel dev: this package is a one-file asset delivery mechanism for a framework you're not using. Copy the JS once if you must, pin a current moment version, wrap it behind a Blade component, and plan the Day.js migration now — the bundle will never be updated.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route