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

Laravel Dymo Printer Laravel Package

graystackit/laravel-dymo-printer

A Laravel integration for DYMO label printers that helps you send label print jobs directly from your PHP application, with simple configuration and helpers for building and formatting labels. Useful for automating address, barcode, and product labels.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. composer require graystackit/laravel-dymo-printer — supports Laravel 11/12/13 and Livewire 3/4.
  2. Put the scripts in your layout once, at the end of <body>:
    <x-dymo-printer::scripts />
    {{-- or --}}
    @dymoscripts
    
    This sets window.DymoPrinterConfig and loads dymo-system.js + printer-select.js. It does not emit an SDK <script src> — the SDK is injected lazily on first use.
  3. Drop in the picker. Livewire: <livewire:dymo-printer::printer-select />. Plain Blade/REST: the standalone printer-select component. Both need the package scripts from step 2.
  4. Print. Build a payload server-side and hand it to the browser:
    // single label
    DymoPrinter::printViaLivewire(DymoPrinter::forPrint($payload));
    
    // batch
    DymoPrinter::batchViaLivewire(DymoPrinter::forBatch($records), ref: 'shipment-42');
    
    The browser receives dymo:print / dymo:print-batch and reports back dymo:print-success (with count) or dymo:print-error.

Where to look first: config/dymo-printer.php (sdk_url), GraystackIT\DymoPrinter\ScriptAssets (script paths, versioned URLs, effective SDK URL), and resources/js/ (dymo-system.js, printer-select.js, the vendored SDK). Listen for the two result events in your own JS before writing any label logic — that tells you what actually reached DYMO Connect.

First use case: a "Print label" button on an order page that prints one shipping label to the printer the user selected, with an inline success/error toast keyed off dymo:print-success / dymo:print-error.

Implementation Patterns

Server-dispatched, browser-executed. All printing happens client-side through the DYMO Connect software; PHP only builds payloads and emits events. Treat printViaLivewire() / batchViaLivewire() as fire-and-forget notifications — always confirm via the dymo:print-success / dymo:print-error events rather than assuming the call succeeded.

Correlate with ref. Pass an optional $ref to forPrint(), forBatch(), printViaLivewire() or batchViaLivewire(), and it comes back on the result event (null when omitted). Use it for anything the user can trigger repeatedly — queue items, order IDs, a counter — so a stale success toast can't be attributed to the wrong job.

window.addEventListener('dymo:print-success', (e) => {
    // e.detail.ref, e.detail.count (always present; 1 for a single label)
});
window.addEventListener('dymo:print-error', (e) => {
    // e.detail.ref — message is always present, even for non-Error rejections
});

Standalone / REST usage. Skip Livewire entirely: include the scripts, keep the shared dymoPrinterSelectStandalone factory (registered on alpine:init, also exposed as a window global), and dispatch the events yourself:

window.dispatchEvent(new CustomEvent('dymo:print', { detail: { ...payload, ref: 'x' } }));

Vite bundling. Import the package entry from your app bundle instead of @dymoscripts:

import '../../vendor/graystackit/laravel-dymo-printer/resources/js/index.js';

It imports the vendored SDK with ?url, so Vite pins and content-hashes it as a static asset. If you need a different SDK location, call DymoSystem.configure({ sdkUrl }) — the URL is read at injection time, not at module evaluation, so configuring after hoisted imports is safe.

Self-hosting the assets. php artisan vendor:publish --tag=dymo-printer-assets now publishes exactly public/vendor/dymo-printer, including the vendored SDK. Point DYMO_SDK_URL at the published file and set :load-sdk="false" on the scripts component so the page owns loading.

Batch printing. Batch is now a single LabelSet sent with one printAsync() call. Payload fields the template has no object for are skipped rather than failing the whole batch — so a slightly over-eager payload won't break printing, but a template/field mismatch will silently drop data.

Integration tip: render the picker once per page and persist the chosen printer name in your own state; re-mounting on every Livewire update causes needless re-initialisation and re-fetches of the printer list.

Gotchas and Tips

  • Nothing prints without DYMO Connect running on the client. It's Windows/Mac desktop software; this package cannot print from a server, a queue worker, or a headless browser. Surface a clear "start DYMO Connect and retry" message — a failed SDK load or init() is deliberately not cached, so a retry button genuinely works.
  • The SDK must load as a classic script. It is injected with document.createElement('script') on first need, not parsed from markup (a parsed <script src> may never execute when Livewire inserts the HTML). Don't convert it to an ES module import, and don't duplicate a manual <script src> tag — DymoSystem skips injection only when window.dymo.label.framework exists or an SDK script element is already present.
  • Re-evaluation is guarded, but don't fight it. wire:navigate and re-hashed bundles re-run the script; a per-document registry (window.__dymoPrinterSystem) ensures the SDK loads once and replaces rather than duplicates the print listeners. Keep data-navigate-once on the script tags and don't strip it.
  • sdk_url is null by default, meaning the package's pinned, vendored SDK served from the dymo-printer.sdk route. If your app has global auth or a strict CSP, make sure /dymo-printer/*.js stays publicly reachable — otherwise you get a silent "SDK never loaded" and a timeout naming the missing URL.
  • Cache busting is automatic — scripts are linked with a content-hash ?v=. Don't append your own query string. If you publish assets, re-run the publish tag after upgrades or you'll serve the old SDK.
  • Livewire 4 namespace: <livewire:dymo-printer::printer-select /> previously threw ComponentNotFoundException; the package now registers the dymo-printer namespace itself. Delete any Livewire::addNamespace('dymo-printer', …) workaround.
  • The Livewire picker's root <div> must stay first. auto_load_scripts now loads scripts via @assets at the end of the root element specifically because a leading @if made Livewire emit a <!--[if BLOCK]--> comment and break nesting with "Invalid Livewire child tag name". Don't wrap the component in conditional Blade.
  • auto_load_scripts is for nested use. The inline factory script is gone because it never reliably ran inside a nested Livewire child; rely on the shared dymoPrinterSelect factory instead of adding your own <script>.
  • Batch failures no longer fall back to label-by-label printing — intentionally, since that could reprint labels that already came out. If a batch fails, the job is reported and nothing further is attempted; only an SDK without LabelSetBuilder prints one call per label. Design your UX around "batch failed, check the printer" rather than "it'll retry individually".
  • printAsync() reports success only once DYMO Connect accepted the job, and a rejected job (false) surfaces as dymo:print-error. Don't treat "no exception thrown" as "label came out"; the printer can still jam after acceptance.
  • QR codes: setObjectText() alone only patches <DataString>, which DYMO Connect ignores — the package now also patches <TextDataHolder><Value>. If you have custom QR handling of your own, patch both or you'll print the template placeholder.
  • Init errors are only diagnosed after a failure. checkEnvironment() threw _createFramework.resetFramework is not a function when called before init(), so it now runs only post-failure. Expect the first error you see to be the real one, not an environment probe.
  • dymo:print-success always carries count (1 for a single label) and ref is null when omitted — update any listener written against the old shape.
  • Template field names are the contract. Use setText()-compatible field names matching the .dymo/DYMO Connect template's objects; unknown payload keys are skipped silently, which is forgiving but makes typos hard to spot. Log the payload next to the template when output looks blank.
  • Extension point: DymoSystem.configure({ sdkUrl }) is the supported hook for a private CDN, a version-pinned mirror, or a future SDK upgrade without forking — the vendored file's header documents the pinned commit (2182e50…) and how to bump it.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
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