Use Electron-Vue to build Electron/Vue.js application with Bootstrap v4 -- DISRECOMMENDED

By: ( +David Herron; Date: June 30, 2018

Tags: Node.JS » Electron

Using Vue.js in an Electron app means dealing with using Webpack to build/package the components and other assets. The most effective way to put this together is the Electron-Vue package, which builds itself as "Boilerplate for making electron applications built with Vue.js". What that means is Electron-Vue is a pre-built application template and build infrastructure to simplify running Electron/Vue applications in development mode, and to package Electron/Vue applications for distribution.

This article is part of a series on kicking the tires of Electron application development. See:

Vue.js is a highly performant lightweight framework for managing client-side data and communications between portions of an application. It is very popular, though it is overshadowed by React (of course). It does not contain any user interface components. For that, in this article we'll turn to the venerable Bootstrap library. As we're just kicking the tires, the UI won't be very much, just enough to show that Vue is doing things with components, and that Bootstrap is up and functioning.

Bootstrap is a highly popular CSS+JavaScript framework for user facing niceness. It contains a bunch of prebaked well defined well tested compnents for building HTML and JavaScript user interfaces. Bootstrap includes an advanced responsive web page framework based on Flexbox. While there are plenty of alternative web UI frameworks, Bootstrap is a good choice.

It's possible to avoid using the Electron-Vue application template -- if you want to spend the time to learn Webpack and Babel sufficiently to set up your own build framework. Before turning to Electron-Vue I tried to roll my own, and while I got quite a ways a couple stumpers had me turn to Electron-Vue for the pragmatic choice of just getting something working.


Turns out that it's strongly recommended to NOT use Bootstrap or jQuery with Vue.js.

The problem is that Vue.js wants to be in control of the DOM manipulations. Bootstrap and jQuery both perform DOM manipulations.

With the following instructions it's clear one can easily get Bootstrap code running in a Vue.js app, but there are difficulties aplenty by proceeding very far in using Bootstrap with Vue.js.


To start, lets build the Electron-Vue demo application:

$ sudo npm install -g vue-cli
$ vue init simulatedgreg/electron-vue electron-vue-bootstrap

? Application Name electron-vue-bootstrap
? Project description An electron-vue project
? Select which Vue plugins to install vue-electron, vue-router
? Use linting with ESLint? No
? Set up unit testing with Karma + Mocha? No
? Set up end-to-end testing with Spectron + Mocha? No
? What build tool would you like to use? builder
? author David Herron <>

   vue-cli · Generated "electron-vue-bootstrap".


All set. Welcome to your new electron-vue project!

Make sure to check out the documentation for this boilerplate at

Next Steps:

  $ cd electron-vue-bootstrap
  $ yarn (or `npm install`)
  $ yarn run dev (or `npm run dev`)

The first step installs vue-cli which is a command-line tool for Vue development. The primary function it provides is the init command with which to download template applications. The lines with ? characters is an interactive dialog used by vue-cli to customize the application setup.

As it says, you then have three steps to perform.

$ cd electron-vue-bootstrap/
$ npm install
npm WARN deprecated babel-preset-babili@0.1.4: babili has been renamed to babel-minify. Please update to babel-preset-minify
$ npm run dev
If all went well, you'll see a simple application screen with a few links to documentation. It's a nice confirmation that we can quickly get a new app running, but of course this isn't what we want to use.

Rebuilding the template application

We don't want to just run the demo app, we want to prove we can build a custom app using the Electron/Vue.js/Bootstrap toolchain. That means ripping out most of what we were given, replacing it all with a few simple bits of code.

In package.json add these three lines to the dependencies section.

"bootstrap": "^4.1.1",
"jquery": "^3.3.1",
"popper.js": "^1.12.9"

These three packages are the base required by Bootstrap v4, and the version numbers are more-or-less correct. Once you've made this change re-run npm install to install the dependencies.

You may want to look at .babelrc and perhaps adjust some things. I'm concerned about this:

"presets": [
  ["env", {
    "targets": { "node": 7 }

Wouldn't be better to target Node.js 8? That's where we get async/await functions and wouldn't it be best if our electron app directly used those functions rather than the transpiled equivalents?

Another directory to consult is .electron-vue since this is where the build tools are kept. But, where we need to turn our attention is the src directory.

You'll find this:

The directory src/main contains code for the Main process, while src/renderer contains code for the Renderer processes.

Recall that Electron has a multi-process model. The Main process manages the overall application and is a Node.js application with no visible user interface. Instead it sends messages back and forth with the Renderer windows. The Renderer processes wrap around Chromium browser windows, and are what contain client-side logic.

In src/renderer/assets you'll place things like image or CSS files. In src/renderer/components you'll place code for Vue components. Finally, index.ejs provides the HTML for the main window.

In src/renderer/main.js is the main JavaScript for the renderer windows, and by default the App component drives the main window.

In index.ejs the code <div id="app"></div> is where the main application lands.

Adding Bootstrap to the main window

The Bootstrap team has some excellent documentation, including the base structure for the HTML in your web pages. But, we have to do it a little differently because of how certain things work in the Electron environment.

In the <head> section of index.ejs add this:

<link rel="stylesheet" 
    window.jQuery = window.$ = require('jquery');

The first element is the normal recommendation, to load bootstrap.css. However we are not loading from the Bootstrap CDN as recommended by the Bootstrap team.

We should strongly avoid loading code from external sources in Electron. There are potential security reasons for this, especially as Electron code runs with different privilege settings than regular browser code. In Electron JavaScript can directly access the file system and do other things that are locked out in browsers. The other reason to not use external dependencies is that we cannot assume the Electron app will always have Internet access.

Earlier when we added Bootstrap, jQuery and Popper dependencies in package.json we ensured that each library was installed in node_modules. Take a look in each package and you'll see each package has client-side code, and we can simply load these things in the HTML as shown here.

The initialization of jQuery in Electron must follow a different practice than normal. The issue is that the jQuery library detects it is being run in Node.js and does not initialize correctly for Electron. For details see Loading jQuery and Bootstrap in Electron app has a curious bug

At the bottom of index.ejs, just before the closing </body> tag, add these lines:

<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<!-- script src="./node_modules/jquery/dist/jquery.js" crossorigin="anonymous"></script -->
<script src="./node_modules/popper.js/dist/umd/popper.js" crossorigin="anonymous"></script>
<script src="./node_modules/bootstrap/dist/js/bootstrap.js" crossorigin="anonymous"></script>

We've commented out the recommended jQuery thing because of what we said earlier. The other two lines are directly from the Bootstrap documentation except for the insertion of umd into the path for popper.js.

At this point you can run the application again (npm run dev) but nothing will have changed. It's useful to ensure there are no errors at this point.

The next step is to replace the contents of src/renderer/components/LandingPage.vue with the folloiwng:

  <div id="wrapper" class="container-fluid">
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <a class="navbar-brand" href="#">Navbar</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>

      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item active">
            <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
          <li class="nav-item">
            <a class="nav-link" href="#">Link</a>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
              <a class="dropdown-item" href="#">Action</a>
              <a class="dropdown-item" href="#">Another action</a>
              <div class="dropdown-divider"></div>
              <a class="dropdown-item" href="#">Something else here</a>
          <li class="nav-item">
            <a class="nav-link disabled" href="#">Disabled</a>
        <form class="form-inline my-2 my-lg-0">
          <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
          <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    <div class="row">
      <div class="col">
        <div class="jumbotron">
          {{ msg }}
    <div class="row">
      <div class="col-sm">
        One of three columns
      <div class="col-sm">
        One of three columns
      <div class="col-sm">
        One of three columns

  export default {
    name: 'landing-page',
    data () {
      return {
        msg: 'Welcome to Your Vue.js App'

  @import url('');

The <script></script> section simply sets up a data item, msg that we can display in the template. That will be enough to demonstrate Vue is functioning. If your home page had additional components, they'd be imported here.

The <template></template> section is simply some sample Bootstrap code I threw together. It doesn't include any actual functionality. I wanted to demonstrate Bootstrap layout, navigation bar, dropdowns, and that Vue works. This section is where your application HTML goes.

The <style></style> section is where CSS declarations go. The Google Fonts reference is inherited from the template Electron-Vue application.

Running the application in development mode

Running in development mode is this easy:

$ npm run dev

> electron-vue-bootstrap@0.0.0 dev /Volumes/Extra/sourcerer/004-electron/electron-vue-bootstrap
> node .electron-vue/dev-runner.js

         ___                      __                                                                
   __   /\_ \       __     ___   /\ \__    _ __    ___     ___              __  __  __  __     __   
 / ,.`\ \//\ \    / ,.`\  /'___\ \ \ ,_\  /\` __\ / __`\ /' _ `\   _______ /\ \/\ \/\ \/\ \  / ,.`\ 
/\  __/   \_\ \_ /\  __/ /\ \__/  \ \ \/  \ \ \/ /\ \_\ \/\ \/\ \ /\______\\ \ \/ |\ \ \_\ \/\  __/ 
\ \____\  /\____\\ \____\\ \____\  \ \ \_  \ \_\ \ \____/\ \_\ \_\\/______/ \ \___/ \ \____/\ \____\
 \/____/  \/____/ \/____/ \/____/   \ \__\  \/_/  \/___/  \/_/\/_/           \/__/   \/___/  \/____/
  getting ready...

┏ Main Process ---------------


┗ ----------------------------

If all goes well you'll see this:

The dropdown will work etc. Because it is in development mode the View menu includes choices to open the Developer Tools, at which point you have the full power of the Chrome Dev Tools at your finger-tips. That's a key advantage to developing on Electron, the Dev Tools. No other GUI framework has this capability built in.

As I said earlier, nothing is attached to anything except you'll see the {{ msg }} section in the template got replaced by our message. That's where we prove Vue is functioning.

Building the application for distribution

The Electron-Vue bundles two methods to bundle the application. We initialized this using electron-builder and therefore we must consult this documentation: (

You can instead initialize with electron-packager.

Build as so:

$ npm run build

> electron-vue-bootstrap@0.0.0 build /Volumes/Extra/sourcerer/004-electron/electron-vue-bootstrap
> node .electron-vue/build.js && electron-builder

 ___              __                        __                       ___       __    
/\_ \       __   /\ \__     ____           /\ \       __  __   __   /\_ \     /\ \   
\//\ \    / ,.`\ \ \ ,_\   / ,__\  _______ \ \ \____ /\ \/\ \ /\_\  \//\ \    \_\ \  
  \_\ \_ /\  __/  \ \ \/  /\__, `\/\______\ \ \  ,. \\ \ \_\ \\/\ \   \_\ \_ /\ ,. \ 
  /\____\\ \____\  \ \ \_ \/\____/\/______/  \ \____/ \ \____/ \ \ \  /\____\\ \____\
  \/____/ \/____/   \ \__\ \/___/             \/___/   \/___/   \/_/  \/____/ \/___ /

  ✔ building main process
  ✔ building renderer process


 OKAY  take it away `electron-builder`

  • electron-builder version=19.56.2
  • loaded configuration file=package.json ("build" field)
  • writing effective config file=build/electron-builder.yaml
  • no native production dependencies
  • packaging       platform=darwin arch=x64 electron=1.8.7 appOutDir=build/mac


  • building        target=macOS zip arch=x64 file=build/
  • building        target=DMG arch=x64 file=build/electron-vue-bootstrap-0.0.0.dmg
  • building block map blockMapFile=build/electron-vue-bootstrap-0.0.0.dmg.blockmap

And you'll end up with this directory:

$ ls build/
electron-builder.yaml				electron-vue-bootstrap-0.0.0.dmg		icons		electron-vue-bootstrap-0.0.0.dmg.blockmap	mac
And, double-clicking the DMG file gets you this familiar-looking installation window.

If you follow through with the installation, you end up with a familiar application icon in the Applications folder which you can double-click and run.

« With a Node.js based REST service, is it okay to not use a front-end framework like React or Vue.js? Quickly start a new Electron and Vue.js application project, »
2016 Election 2018 Elections Acer C720 Ad block Affiliate marketing Air Filters Air Quality Air Quality Monitoring AkashaCMS Amazon Amazon Kindle Amazon Web Services America Amiga and Jon Pertwee Android Anti-Fascism AntiVirus Software Apple Apple Flexgate Apple Hardware History Apple Hardware Mistakes Apple iPhone Apple iPhone Hardware April 1st Arduino ARM Compilation Artificial Intelligence Astronomy Astrophotography Asynchronous Programming Authoritarianism Automated Social Posting AWS DynamoDB AWS Lambda Ayo.JS Bells Law Big Brother Big Data Big Finish Big Science Bitcoin Mining Black Holes Blade Runner Blockchain Blogger Blogging Books Botnets Cassette Tapes Cellphones China China Manufacturing Christopher Eccleston Chrome Chrome Apps Chromebook Chromebox ChromeOS CIA CitiCards Citizen Journalism Civil Liberties Climate Change Clinton Cluster Computing Command Line Tools Comment Systems Computer Accessories Computer Hardware Computer Repair Computers Conservatives Cross Compilation Crouton Cryptocurrency Curiosity Rover Currencies Cyber Security Cybermen Cybersecurity Daleks Darth Vader Data backup Data Formats Data Storage Database Database Backup Databases David Tenant DDoS Botnet Department of Defense Department of Justice Detect Adblocker Developers Editors Digital audio Digital Nomad Digital Photography Direct Attach Storage Diskless Booting Disqus DIY DIY Repair DNP3 Do it yourself Docker Docker MAMP Docker Swarm Doctor Who Doctor Who Paradox Doctor Who Review Drobo Drupal Drupal Themes DuckDuckGo DVD E-Books E-Readers Early Computers eGPU Election Hacks Electric Bicycles Electric Vehicles Electron Eliminating Jobs for Human Emdebian Encabulators Energy Efficiency Enterprise Node EPUB ESP8266 Ethical Curation Eurovision Event Driven Asynchronous Express Face Recognition Facebook Fake Advertising Fake News Fedora VirtualBox Fifth Doctor File transfer without iTunes FireFly Flash Flickr Fraud Freedom of Speech Front-end Development G Suite Gallifrey Gig Economy git Github GitKraken Gitlab GMAIL Google Google Adsense Google Chrome Google Gnome Google+ Government Spying Great Britain Green Transportation Hate Speech Heat Loss Hibernate High Technology Hoax Science Home Automation HTTP Security HTTPS Human ID I2C Protocol Image Analysis Image Conversion Image Processing ImageMagick In-memory Computing Incognito Mode InfluxDB Infrared Thermometers Insulation Internet Internet Advertising Internet Law Internet of Things Internet Policy Internet Privacy iOS iOS Devices iPad iPhone iPhone hacking Iron Man iShowU Audio Capture iTunes Janet Fielding Java JavaFX JavaScript JavaScript Injection JDBC John Simms Journalism Joyent jQuery Kaspersky Labs Kext Kindle Kindle Marketplace Large Hadron Collider Lets Encrypt LibreOffice Linux Linux Hints Linux Single Board Computers Logging Mac Mini Mac OS Mac OS X Mac Pro MacBook Pro Machine Learning Machine Readable ID Macintosh macOS macOS High Sierra macOS Kext MacOS X setup Make Money Online Make Money with Gigs March For Our Lives MariaDB Mars Mass Violence Matt Lucas MEADS Anti-Missile Mercurial MERN Stack Michele Gomez Micro Apartments Microsoft Military AI Military Hardware Minification Minimized CSS Minimized HTML Minimized JavaScript Missy Mobile Applications Mobile Computers MODBUS Mondas Monetary System MongoDB Mongoose Monty Python MQTT Music Player Music Streaming MySQL NanoPi Nardole NASA Net Neutrality Network Attached Storage Node Web Development Node.js Node.js Database Node.js Performance Node.js Testing Node.JS Web Development Node.x North Korea npm NSA NVIDIA NY Times Online advertising Online Community Online Fraud Online Journalism Online News Online Photography Online Video Open Media Vault Open Source Open Source and Patents Open Source Governance Open Source Licenses Open Source Software OpenAPI OpenJDK OpenVPN Palmtop PDA Patrick Troughton PayPal Paywalls Personal Flight Peter Capaldi Peter Davison Phishing Photography PHP Plex Plex Media Server Political Protest Politics Postal Service Power Control President Trump Privacy Private E-mail server Production use Public Violence Raspberry Pi Raspberry Pi 3 Raspberry Pi Zero ReactJS Recaptcha Recycling Refurbished Computers Remote Desktop Removable Storage Renewable Energy Republicans Retro Computing Retro-Technology Reviews RFID Rich Internet Applications Right to Repair River Song Robotics Robots Rocket Ships RSS News Readers rsync Russia Russia Troll Factory Russian Hacking Rust SCADA Scheme Science Fiction SD Cards Search Engine Ranking Search Engines Season 1 Season 10 Season 11 Security Security Cameras Server-side JavaScript Serverless Framework Servers Shell Scripts Silence Simsimi Skype SmugMug Social Media Social Media Networks Social Media Warfare Social Network Management Social Networks Software Development Software Patents Space Flight Space Ship Reuse Space Ships SpaceX Spear Phishing Spring Spring Boot Spy Satellites SQLite3 SSD Drives SSD upgrade SSH SSH Key SSL Stand For Truth Strange Parts Swagger Synchronizing Files Tegan Jovanka Telescopes Terrorism The Cybermen The Daleks The Master Time-Series Database Tom Baker Torchwood Total Information Awareness Trump Trump Administration Trump Campaign Twitter Ubuntu Udemy UDOO US Department of Defense Video editing Virtual Private Networks VirtualBox VLC VNC VOIP Vue.js Walmart Weapons Systems Web Applications Web Developer Resources Web Development Web Development Tools Web Marketing Webpack Website Advertising Website Business Models Website Security Weeping Angels WhatsApp William Hartnell Window Insulation Windows Windows Alternatives Wordpress World Wide Web Yahoo YouTube YouTube Adpocalypse YouTube Monetization