Print the stickers/labels using ElectronJS Desktop application

Rakesh Ostwal
5 min readSep 25, 2021

--

In this article, we are going to talk about how to print the stickers of specific size (say 10" X 10") using Vue-ElectronJS Desktop application

We see the product information sticker being sticked on the product with its product and price information. Or there are many industries where the products are being tested and based on its results the testing application creates a sticker and that sticker is sticked to the tested product.

How these prints are generated and printed on sticker?

We are going to see exactly that in this article.

We are using a VueJS with ElectronJS to build our application. As ElectronJS gives us an ability to create the Desktop applications, it also have the inbuilt APIs to create the print statement and return its result.

Printing normal text VS Printing HTML content

When you want to print the normal text, you can directly give the commands from the main window. But when you want the custom HTML designed content to be printed, you must create a new window where you will have the HTML content rendered and then give a command to print the content on this page.

In this article, we will explore the second option of printing the HTML content.

By default ElectronJS, creates a single window and its sufficient when you want to render the application content, but when we want to print a custom/dynamic data, we must have another window that will render this data.

Let’s configure another window:

In you main renderer file, generally located at — src/main/index.js, you will notice the main window being defined here, let’s define another window for rendering the print content

const printerWindow = new BrowserWindow({
show: false,
webPreferences: {
webSecurity: false,
nodeIntegration: true,
nodeIntegrationInWorker: true
},
protocol: 'file'
});

We will keep this window hidden as the end user do not need to see this.

As this window will be rendering the html content, let’s load the html template on this window:

We will need a HTML page to load the html content, let’s define the html page first in src/static/ directory.

static/printer.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
<title>Printer</title>
<style>
body {
font-family: sans-serif !important;
}
@page {
margin: 0;
width: 30mm;
height: 15mm;
}
.a {
padding-left: 100px;
}
</style>
</head>
<body>
<div id='app'>
<div id="printContainer"
style="height: 40px; width: 40px; display: inline-block; margin-left: 5px; margin-top: 5px;">
<span>Hello</span>
</div>
</div>
</body>
</html>

This is very basic HTML page, we will add more brain (using javascript) and content to it in next few steps.

Access this html page in the /src/main/index.js file where we have defined the printerWindow and load it in printerWindow.

const printerUrl = process.env.NODE_ENV === 'development'
? `http://localhost:9080/static/printer.html`
: `file://${__dirname}/static/printer.html`
...
workerWindow.loadURL(workerUrl);
workerWindow.on("closed", () => {
workerWindow = undefined;
});

This will load our html page on the worker window, if you want to check how your html looks, you can enable it from printerWindow definition by changing show to true.

If you want to debug the content of the printer window, you can enable its dev tool using

workerWindow.webContents.openDevTools();

Setting up print content

Now we have setup the basic worker window and are ready to print the content, so let’s add an action that will give the print command.

Let’s take an example of printing student information, we want to print the student’s details like Roll No, Name and Standard as soon as new student is added to the student database.

Here we have a CreateStudent Vue component, I have a method where i save the student details:

...
methods: {
createStudent (student) {
// implementation to save the student
// after student is saved, call the printer to print the student details.
}
}
...

We need to pass the student data to printer.html for it to update the html content and print the data.

To do so, we will be using ipcRender to send the event to the printer.html, where we will have a listener that is listening to the studentCreated event.

So in CreateStudent Vue component, define ipcRenderer and send the studentCreated callback to printer.HTML

createStudent (student) {
...
const ipcRenderer = require("electron").ipcRenderer;
ipcRenderer.send("createStudent", student);
...
}

Sending print content from main window to printer window

As our create student component is on main window, the `studentCreated` callback will not be directly accessed on printer window, we will need to pass the data from main window to printer window.

In src/main/index.js, add a listener to listen to studentCreated callback and then pass this content to worker printerWindow where printer.html will have a listener to catch the student content.

import { ipcMain } from 'electron'ipcMain.on("createStudent", (event, content) => {
workerWindow.webContents.send("createStudent", content);
});

In Printer.html, define a listener to listen to this callback and update the html to print the student information on the printerWindow

...
<body>
<div id='app'>
<div id="printContainer"
style="height: 40px; width: 40px; display: inline-block; margin-left: 5px; margin-top: 5px;">
<!-- <div style="
display: inline-block;
font-size: 12px;
float: left;
font-weight: 600;
">
<span>Name: {{studentName}}</span><br />
<span>Roll NO: {{rollNo}}</span><br />
<span>class: {{standard}}</span><br />
</div> -->
</div>
</div>
</body>
<script>
//Introducing an ipcRenderer object
const {
ipcRenderer
} = require('electron');

new Vue({
el: "#app",
data: {
studentName: '',
rollNo: '',
standard: '',
},
mounted() {
ipcRenderer.on('createStudent', (e, student) => { //Receiving response
console.log("student info", student)
this.studentName = student.name;
this.rollNo = student.rollNo;
this.standard = student.standard;
// As Vue updates this content on the html content, now give the callback to printer window that content is created it is ready to print
ipcRenderer.send('readyToPrintPDF') //Communicate the message to the process of the page where webview is located
})
},
methods: {}
})
</script>
...

In above code, we have updated the content on printer window and also sent the call back to printer window that the content is ready to print.

Now in src/main/index.js where we have defined the printerWindow, let’s add the listener to the readyToPrintPDF callback and give the print command to the printerUrl

ipcMain.on("readyToPrintPDF", (event) => {
// check if at-least 1 printer is connected
let printers = workerWindow.webContents.getPrinters();
// send the command to print the content
if (printers != null && printers.length > 0) {
workerWindow.webContents.print({silent: true}, (success) => {
mainWindow.webContents.send('printCompleted', success);
})
} else {
mainWindow.webContents.send('printCompleted', false);
}
});

As you see, we are checking the printers and the giving the print command on printerWindow. Once the print is successful or fails, we will send back the callback to the Create Student Vue Component so that, app will act based on its result.

In Create Student component, add a listener to listen to the printCompleted event.

...
mounted() {
ipcRenderer.on("printCompleted", (success) => {
if (success) {
// Do the next OP
} else {
// DO next OP
}
});
}

You can checkout the complete code of this implementation on my public gist files:

--

--

Rakesh Ostwal

Tech lead, Software Development enthusiastic, fullstack developer