You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

vue-cli-plugin-electron-builder

Package Overview
Dependencies
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vue-cli-plugin-electron-builder - npm Package Compare versions

Comparing version

to
3.0.0-alpha.0

lib/testWithPlaywright.js

15

generator/index.js

@@ -17,3 +17,2 @@ const fs = require('fs')

api.render('./templates/base', {
spectronSupport: options.electronBuilder.addTests,
vue3: /^(\^?)3/.test(((pkg || {}).dependencies || {}).vue)

@@ -103,12 +102,2 @@ })

}
const dependencies = {}
if (testFramework) {
// Spectron version should be electron version + 2
devDependencies.spectron =
parseInt(
(electronVersion || pkg.devDependencies.electron).match(/^\^(\d*)\./)[1]
) +
2 +
'.0.0'
}
if (testFramework === 'mocha') {

@@ -119,6 +108,4 @@ devDependencies['chai-as-promised'] = '^7.1.1'

scripts,
dependencies,
devDependencies,
main: 'background.js'
devDependencies
})
}

@@ -19,6 +19,2 @@ 'use strict'

webPreferences: {
<% if (spectronSupport) { %>
// Required for Spectron testing
enableRemoteModule: !!process.env.IS_TEST,
<% } %>
// Use pluginOptions.nodeIntegration, leave this alone

@@ -25,0 +21,0 @@ // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info

/**
* @jest-environment node
*/
import spectron from 'spectron'
import { testWithSpectron } from 'vue-cli-plugin-electron-builder'
import { testWithPlaywright } from 'vue-cli-plugin-electron-builder'
jest.setTimeout(50000)

@@ -10,24 +9,16 @@

// Wait for dev server to start
const { app, stopServe } = await testWithSpectron(spectron)
const win = app.browserWindow
const client = app.client
const { app, stop } = await testWithPlaywright()
const win = await app.firstWindow()
await win.waitForLoadState('domcontentloaded')
// Window was created
expect(await client.getWindowCount()).toBe(1)
// It is not minimized
expect(await win.isMinimized()).toBe(false)
// Window is visible
expect(await win.isVisible()).toBe(true)
// Size is correct
const { width, height } = await win.getBounds()
expect(width).toBeGreaterThan(0)
expect(height).toBeGreaterThan(0)
expect(app.windows().length).toBe(1)
// App is loaded properly
expect(
/Welcome to Your Vue\.js (\+ TypeScript )?App/.test(
await (await app.client.$('#app')).getHTML()
await win.innerText('#app')
)
).toBe(true)
await stopServe()
await stop()
})

@@ -1,2 +0,2 @@

import { Application, AppConstructorOptions } from 'spectron'
import { ElectronApplication } from 'playwright-core'
import { Configuration as ElectronBuilderOptions } from 'electron-builder'

@@ -7,51 +7,44 @@ import * as ChainableWebpackConfig from 'webpack-chain'

/**
Do not launch spectron.
You will have to launch it on your own.
*/
noSpectron: boolean
/** Launch server in dev mode, not in production. */
forceDev: boolean
/** Custom spectron options.These will be merged with default options. */
spectronOptions: AppConstructorOptions
/** Do not start app or wait for it to load.
You will have to run app.start() and app.client.waitUntilWindowLoaded() yourself.
*/
noStart: boolean
/** Set custom Vue env mode. Defaults to 'test' */
mode: string
Do not launch Playwright.
You will have to launch it on your own.
*/
noPlaywright?: boolean
/** Custom Playwright launch options. These will be merged with default options. */
launchOptions?: Object
/** Set custom Vue env mode. Defaults to 'production' */
mode?: string
}
interface Server {
/** Spectron instance. */
app: Application
interface ElectronInstance {
/** Playwright application instance. */
app: ElectronApplication
/** Close app instance and stop dev server (must be called to prevent continued async operations). */
stop: () => Promise<ElectronApplication>
/** URL of dev server. */
url: string
/** Close spectron and stop dev server (must be called to prevent continued async operations). */
stopServe: () => Promise<Application>
serverUrl: string
/** Log of dev server. */
stdout: string
serverStdout: string
}
/**
Run electron:serve, but instead of launching Electron it returns a Spectron Application instance.
Used for e2e testing with Spectron.
Run electron:serve, but instead of launching Electron it returns a Playwright Application instance.
Used for e2e testing with Playwright.
*/
export function testWithSpectron(spectron: any, options?: Partial<Options>): Promise<Server>
export function testWithPlaywright(options?: Options): Promise<ElectronInstance>
export type PluginOptions = {
builderOptions?: ElectronBuilderOptions,
chainWebpackMainProcess?: (config?: ChainableWebpackConfig) => void,
chainWebpackRendererProcess?: (config?: ChainableWebpackConfig) => void,
mainProcessFile?: string,
rendererProcessFile?: string,
mainProcessWatch?: string[],
mainProcessArgs?: string[],
outputDir?: string,
disableMainProcessTypescript?: boolean,
mainProcessTypeChecking?: boolean,
customFileProtocol?: string,
removeElectronJunk?: boolean,
externals?: string[],
nodeModulesPath?: string[],
builderOptions?: ElectronBuilderOptions
chainWebpackMainProcess?: (config?: ChainableWebpackConfig) => void
chainWebpackRendererProcess?: (config?: ChainableWebpackConfig) => void
mainProcessFile?: string
rendererProcessFile?: string
mainProcessWatch?: string[]
mainProcessArgs?: string[]
outputDir?: string
disableMainProcessTypescript?: boolean
mainProcessTypeChecking?: boolean
customFileProtocol?: string
externals?: string[]
nodeModulesPath?: string[]
preload?: string | Record<string, string>
nodeIntegration?: boolean
}

@@ -19,3 +19,3 @@ const TerserPlugin = require('terser-webpack-plugin')

const { chainWebpack, getExternals } = require('./lib/webpackConfig')
const webpackMerge = require('webpack-merge')
const { merge: webpackMerge } = require('webpack-merge')

@@ -45,5 +45,2 @@ module.exports = (api, options) => {

: []
if (pluginOptions.experimentalNativeDepCheck) {
process.env.VCPEB_EXPERIMENTAL_NATIVE_DEP_CHECK = true
}

@@ -76,4 +73,4 @@ const removeArg = (arg, count, rawArgs) => {

// Import the yargs options from electron-builder
const configureBuildCommand = require('electron-builder/out/builder')
.configureBuildCommand
const configureBuildCommand =
require('electron-builder/out/builder').configureBuildCommand
// Prevent custom args from interfering with electron-builder

@@ -108,3 +105,3 @@ removeArg('--mode', 2, rawArgs)

// Build with electron-builder
buildApp(args.skipElectronBuild)
buildApp()
} else {

@@ -149,5 +146,3 @@ const bundleOutputDir = path.join(outputDir, 'bundled')

})
// Set the base url so that the app protocol is used
options.baseUrl = pluginOptions.customFileProtocol || 'app://./'
// Set publicPath as well (replaced baseUrl since @vue/cli 3.3.0)
// Set the base url (publicPath) so that the app protocol is used
options.publicPath = pluginOptions.customFileProtocol || 'app://./'

@@ -228,6 +223,6 @@ info('Bundling render process:')

buildApp(args.skipElectronBuild)
buildApp()
})
} else {
buildApp(args.skipElectronBuild)
buildApp()
}

@@ -242,9 +237,9 @@ })

api.resolve(mainProcessFile),
api.resolve(`${outputDir}/bundled/background.js`)
api.resolve(`${outputDir}/bundled/index.js`)
)
buildApp(args.skipElectronBuild)
buildApp()
}
}
function buildApp (skip) {
if (skip) {
function buildApp () {
if (args.skipElectronBuild) {
console.log('Not building app as --skipElectronBuild was passed')

@@ -474,3 +469,3 @@ return

info(
'If you are using Spectron, make sure to set the IS_TEST env variable to true.'
'If you are using Playwright, make sure to set the IS_TEST env variable to true.'
)

@@ -481,3 +476,3 @@ info(

} else if (args.headless) {
// Log information for spectron
// Log information for playwright
console.log(`$outputDir=${outputDir}`)

@@ -526,16 +521,2 @@ console.log(`$WEBPACK_DEV_SERVER_URL=${server.url}`)

if (pluginOptions.removeElectronJunk === false) {
// Pipe output to console
child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)
} else {
// Remove junk terminal output (#60)
child.stdout
.pipe(require('./lib/removeJunk.js')())
.pipe(process.stdout)
child.stderr
.pipe(require('./lib/removeJunk.js')())
.pipe(process.stderr)
}
child.on('exit', onChildExit)

@@ -550,42 +531,2 @@ }

)
api.registerCommand(
'build:electron',
{
description:
'[deprecated, use electron:build instead] build app with electron-builder',
usage: 'vue-cli-service build:electron [electron-builder options]',
details:
'All electron-builder command line options are supported.\n' +
'See https://www.electron.build/cli for cli options\n' +
'See https://nklayman.github.io/vue-cli-plugin-electron-builder/ for more details about this plugin.'
},
(args, rawArgs) => {
warn('This command is deprecated. Please use electron:build instead.')
return api.service.run(
'electron:build',
{ ...args, _: ['First arg is removed', ...args._] },
['First arg is removed', ...rawArgs]
)
}
)
api.registerCommand(
'serve:electron',
{
description:
'[deprecated, use electron:serve instead] serve app and launch electron',
usage: 'vue-cli-service serve:electron',
details:
'See https://nklayman.github.io/vue-cli-plugin-electron-builder/ for more details about this plugin.'
},
(args, rawArgs) => {
warn('This command is deprecated. Please use electron:serve instead.')
return api.service.run(
'electron:serve',
{ ...args, _: ['First arg is removed', ...args._] },
['First arg is removed', ...rawArgs]
)
}
)
}

@@ -608,6 +549,3 @@

const config = new Config()
config
.mode(NODE_ENV)
.node.set('__dirname', false)
.set('__filename', false)
config.mode(NODE_ENV).node.set('__dirname', false).set('__filename', false)
// Set externals

@@ -618,4 +556,3 @@ config.externals(getExternals(api, pluginOptions))

.path(api.resolve(outputDir + (isBuild ? '/bundled' : '')))
// Electron will not detect background.js on dev server, only index.js
.filename('[name].js')
.filename('index.js')
const envVars = {}

@@ -668,3 +605,3 @@ if (isBuild) {

.plugin('friendly-errors')
.use(require('friendly-errors-webpack-plugin'), [
.use(require('@soda/friendly-errors-webpack-plugin'), [
{

@@ -693,5 +630,3 @@ additionalTransformers: [transformer],

mainConfig.target('electron-main')
mainConfig
.entry(isBuild ? 'background' : 'index')
.add(api.resolve(mainProcessFile))
mainConfig.entry('index').add(api.resolve(mainProcessFile))

@@ -720,7 +655,5 @@ preloadConfig.target('electron-preload')

module.exports.defaultModes = {
'build:electron': 'production',
'serve:electron': 'development',
'electron:build': 'production',
'electron:serve': 'development'
}
module.exports.testWithSpectron = require('./lib/testWithSpectron')
module.exports.testWithPlaywright = require('./lib/testWithPlaywright')

@@ -0,41 +1,90 @@

/*
Slightly modified from:
Reasonably Secure Electron
Copyright (C) 2019 Bishop Fox
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-------------------------------------------------------------------------
Implementing a custom protocol achieves two goals:
1) Allows us to use ES6 modules/targets for Angular
2) Avoids running the app in a file:// origin
*/
import { protocol } from 'electron'
import * as fs from 'fs'
import * as path from 'path'
import { readFile } from 'fs'
import { URL } from 'url'
export default (scheme, customProtocol) => {
(customProtocol || protocol).registerBufferProtocol(
scheme,
(request, respond) => {
let pathName = new URL(request.url).pathname
pathName = decodeURI(pathName) // Needed in case URL contains spaces
const mimeTypes = {
'.js': 'text/javascript',
'.mjs': 'text/javascript',
'.html': 'text/html',
'.htm': 'text/html',
'.json': 'application/json',
'.css': 'text/css',
'.svg': 'application/svg+xml',
'.ico': 'image/vnd.microsoft.icon',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.map': 'text/plain'
}
readFile(path.join(__dirname, pathName), (error, data) => {
if (error) {
console.error(
`Failed to read ${pathName} on ${scheme} protocol`,
error
)
}
const extension = path.extname(pathName).toLowerCase()
let mimeType = ''
function charset (mimeType) {
return ['.html', '.htm', '.js', '.mjs'].some((m) => m === mimeType)
? 'utf-8'
: null
}
if (extension === '.js') {
mimeType = 'text/javascript'
} else if (extension === '.html') {
mimeType = 'text/html'
} else if (extension === '.css') {
mimeType = 'text/css'
} else if (extension === '.svg' || extension === '.svgz') {
mimeType = 'image/svg+xml'
} else if (extension === '.json') {
mimeType = 'application/json'
} else if (extension === '.wasm') {
mimeType = 'application/wasm'
}
function mime (filename) {
const type = mimeTypes[path.extname(`${filename || ''}`).toLowerCase()]
return type || null
}
respond({ mimeType, data })
export default (scheme, customProtocol) =>
(customProtocol || protocol).registerBufferProtocol(scheme, (req, next) => {
const reqUrl = new URL(req.url)
// If the path doesn't start with "/" then path.normalize will not
// resolve all '..' and could lead to path traversal attacks
if (!reqUrl.pathname.startsWith('/')) {
return next({
mimeType: null,
charset: null,
data: null
})
}
)
}
let reqPath = path.normalize(reqUrl.pathname)
if (reqPath === '/') {
reqPath = '/index.html'
}
const reqFilename = path.basename(reqPath)
fs.readFile(path.join(__dirname, reqPath), (err, data) => {
const mimeType = mime(reqFilename)
if (!err && mimeType !== null) {
next({
mimeType: mimeType,
charset: charset(mimeType),
data: data
})
} else {
console.error(err)
next({
mimeType: null,
charset: null,
data: null
})
}
})
})
import { Protocol } from 'electron'
export function createProtocol(scheme: string, customProtocol?: Protocol): void
export function installVueDevtools(forceDownload?: boolean): Promise<string>

@@ -1,2 +0,1 @@

export { default as installVueDevtools } from './installVueDevtools'
export { default as createProtocol } from './createProtocol'
const fs = require('fs')
const semver = require('semver')
const { DefinePlugin } = require('webpack')
const { error } = require('@vue/cli-shared-utils')

@@ -8,9 +8,4 @@ async function chainWebpack (api, pluginOptions, config) {

pluginOptions.chainWebpackRendererProcess || ((config) => config)
const { devDependencies } = require(api.resolve('./package.json'))
const realDirname = semver.gte(
((devDependencies || {}).electron || '12.0.0').replace(/^\^/, ''),
'12.0.0'
)
? '__dirname.replace(/electron\\.asar(\\\\|\\/)renderer/, "app.asar")'
: 'require("electron").remote.app.getAppPath()'
const realDirname =
'__dirname.replace(/electron\\.asar(\\\\|\\/)renderer/, "app.asar")'
if (process.env.IS_ELECTRON) {

@@ -51,14 +46,2 @@ if (pluginOptions.nodeIntegration) {

})
const pkg = require(api.resolve('package.json'))
const semver = require('semver')
const electronVersion = { ...pkg.devDependencies, ...pkg.dependencies }
.electron
// Prefetch requests fail on Electron versions greater than 7
// https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/546
if (
/^\^?(\d|\.)*$/.test(electronVersion) &&
semver.gte(electronVersion.replace('^', ''), '7.0.0')
) {
config.plugins.delete('prefetch')
}
}

@@ -69,19 +52,17 @@ // Apply user config

if (process.env.NODE_ENV === 'test') {
// Configure for mocha-webpack
config.module
.rule('shebang')
.test(/\.js$/)
.use('shebang')
.loader('shebang-loader')
config.externals({
'vue-cli-plugin-electron-builder/lib/testWithSpectron':
'require("vue-cli-plugin-electron-builder/lib/testWithSpectron")',
'vue-cli-plugin-electron-builder':
'require("vue-cli-plugin-electron-builder")'
})
}
// Older generated files expect this
process.env.VUE_APP_NODE_MODULES_PATH = false
// TODO: is this needed?
// if (process.env.NODE_ENV === 'test') {
// // Configure for mocha-webpack
// config.module
// .rule('shebang')
// .test(/\.js$/)
// .use('shebang')
// .loader('shebang-loader')
// config.externals({
// 'vue-cli-plugin-electron-builder/lib/testWithSpectron':
// 'require("vue-cli-plugin-electron-builder/lib/testWithSpectron")',
// 'vue-cli-plugin-electron-builder':
// 'require("vue-cli-plugin-electron-builder")'
// })
// }
}

@@ -116,12 +97,19 @@ // Find all the dependencies without a `main` property or with a `binary` property or set by user and add them as webpack externals

try {
if (process.env.VCPEB_EXPERIMENTAL_NATIVE_DEP_CHECK) {
// If dep is in whitelist, don't add it no matter what
if (userExternalsWhitelist.includes(dep)) {
return depList
}
const name = userExternals.find((name) =>
new RegExp(`^${dep}(/|$)`).test(name)
)
// If dep is listed in user external array, it is an external
if (name) {
// If dep is in whitelist, don't add it no matter what
if (userExternalsWhitelist.includes(dep)) {
return depList
}
const name = userExternals.find((name) =>
new RegExp(`^${dep}(/|$)`).test(name)
)
// If dep is listed in user external array, it is an external
if (name) {
// Use user-provided name if it exists to support subpaths
depList.push(name || dep)
return depList
}
for (const path of nodeModulesPaths) {
// Check if binding.gyp exists
if (fs.existsSync(api.resolve(`${path}/${dep}/binding.gyp`))) {
// If it does, dep is native
// Use user-provided name if it exists to support subpaths

@@ -131,50 +119,14 @@ depList.push(name || dep)

}
for (const path of nodeModulesPaths) {
// Check if binding.gyp exists
if (fs.existsSync(api.resolve(`${path}/${dep}/binding.gyp`))) {
// If it does, dep is native
// Use user-provided name if it exists to support subpaths
depList.push(name || dep)
return depList
}
}
} else {
let pgkString
for (const path of nodeModulesPaths) {
// Check if package.json exists
if (fs.existsSync(api.resolve(`${path}/${dep}/package.json`))) {
// If it does, read it and break
pgkString = fs
.readFileSync(api.resolve(`${path}/${dep}/package.json`))
.toString()
break
}
}
if (!pgkString) {
throw new Error(`Could not find a package.json for module ${dep}`)
}
const pkg = JSON.parse(pgkString)
const name = userExternals.find((name) =>
new RegExp(`^${pkg.name}(/|$)`).test(name)
)
const fields = ['main', 'module', 'jsnext:main', 'browser']
if (
// Not whitelisted
userExternalsWhitelist.indexOf(dep) === -1 &&
// Doesn't have main property
(!fields.some((field) => field in pkg) ||
// Has binary property
!!pkg.binary ||
// Has gypfile property
!!pkg.gypfile ||
// Listed in user-defined externals list
!!name)
) {
// Use user-provided name if it exists, for subpaths
depList.push(name || dep)
}
}
} catch (e) {
console.log(e)
depList.push(dep)
error(
`An error occurred while trying to determine if dependency "${dep}" is native:`,
e
)
error(
'Please manually specify the dependency in the "externals" option, prefixing with a "!" if it should not be externalized.'
)
error(
'See https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/guide.html#native-modules for more details.'
)
}

@@ -181,0 +133,0 @@ return depList

{
"name": "vue-cli-plugin-electron-builder",
"version": "2.1.1",
"version": "3.0.0-alpha.0",
"description": "Easily Build Your Vue.js App For Desktop With Electron",

@@ -24,4 +24,3 @@ "main": "index.js",

"webpack",
"electron-builder",
"electron-webpack"
"electron-builder"
],

@@ -33,43 +32,37 @@ "repository": "https://github.com/nklayman/vue-cli-plugin-electron-builder.git",

"dependencies": {
"@vue/cli-shared-utils": "^4.5.6",
"@soda/friendly-errors-webpack-plugin": "^1.8.1",
"@vue/cli-shared-utils": "^5.0.0-rc.1",
"chokidar": "^3.0.2",
"electron-builder": "^22.2.0",
"execa": "^5.0.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"fs-extra": "^9.0.1",
"fs-extra": "^10.0.0",
"lodash.merge": "^4.6.1",
"portfinder": "^1.0.16",
"pumpify": "^2.0.1",
"semver": "^7.3.2",
"playwright-core": "^1.17.1",
"shebang-loader": "^0.0.1",
"split2": "^3.0.0",
"terser-webpack-plugin": "^3.0.3",
"through2-filter": "^3.0.0",
"through2-map": "^3.0.0",
"unzip-crx": "^0.2.0",
"webpack": "^4.18.0",
"terser-webpack-plugin": "^5.3.0",
"webpack": "^5.65.0",
"webpack-chain": "^6.0.0",
"webpack-merge": "^4.2.2",
"yargs": "^15.3.1"
"webpack-merge": "^5.8.0",
"yargs": "^16.2.0"
},
"devDependencies": {
"@vue/cli": "^4.0.0",
"@vue/cli-plugin-babel": "^4.0.0",
"@vue/cli-plugin-eslint": "^4.0.0",
"@vue/cli-plugin-typescript": "^4.0.0",
"@vue/cli-plugin-unit-jest": "^4.0.0",
"@vue/cli-plugin-unit-mocha": "^4.0.0",
"@vue/cli-service": "^4.0.0",
"@vue/cli-test-utils": "^4.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"@vue/cli": "^5.0.0-rc.1",
"@vue/cli-plugin-babel": "^5.0.0-rc.1",
"@vue/cli-plugin-eslint": "^5.0.0-rc.1",
"@vue/cli-plugin-typescript": "^5.0.0-rc.1",
"@vue/cli-plugin-unit-jest": "^5.0.0-rc.1",
"@vue/cli-plugin-unit-mocha": "^5.0.0-rc.1",
"@vue/cli-service": "^5.0.0-rc.1",
"@vue/cli-test-utils": "^5.0.0-rc.1",
"@vue/eslint-config-typescript": "^10.0.0",
"@vuepress/plugin-google-analytics": "^1.8.0",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"electron": "^13.1.4",
"electron": "^16.0.5",
"electron-devtools-installer": "^3.1.0",
"eslint": "^7.2.0",
"eslint": "^7.0.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.21.2",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-promise": "^5.0.0",
"eslint-plugin-standard": "^5.0.0",

@@ -79,5 +72,4 @@ "jest": "^24.8.0",

"rimraf": "^3.0.0",
"spectron": "^15.0.0",
"terminal-tasks": "^0.0.5",
"typescript": "^3.9.5",
"typescript": "^4.5.4",
"vue": "^2.5.20",

@@ -84,0 +76,0 @@ "vue-template-compiler": "^2.5.20",

@@ -8,18 +8,18 @@ const path = require('path')

message: 'Choose Electron Version',
default: '^13.0.0',
default: '^16.0.0',
choices: [
{
name: '^11.0.0',
value: '^11.0.0',
short: '^11.0.0'
name: '^14.0.0',
value: '^14.0.0',
short: '^14.0.0'
},
{
name: '^12.0.0',
value: '^12.0.0',
short: '^12.0.0'
name: '^15.0.0',
value: '^15.0.0',
short: '^15.0.0'
},
{
name: '^13.0.0',
value: '^13.0.0',
short: '^13.0.0'
name: '^16.0.0',
value: '^16.0.0',
short: '^16.0.0'
}

@@ -42,3 +42,3 @@ ],

type: 'confirm',
message: 'Add tests with Spectron to your project?',
message: 'Add tests with Playwright to your project?',
when: () => {

@@ -45,0 +45,0 @@ try {

@@ -49,11 +49,12 @@ # Vue CLI Plugin Electron Builder

| [![Yves Hoppe](https://avatars1.githubusercontent.com/u/897638?s=64&v=4)](https://github.com/yvesh) | [![durairajasivam](https://avatars3.githubusercontent.com/u/6660533?s=64&v=4)](https://github.com/durairajasivam) | [![Chris Hayes](https://avatars3.githubusercontent.com/u/6013871?s=64)](https://github.com/Christopher-Hayes) | [![Andrew LeTourneau](https://avatars2.githubusercontent.com/u/2807807?s=64&v=4)](https://github.com/centerorbit) | [![Kalila Lakeworth](https://avatars1.githubusercontent.com/u/69767640?s=64)](https://vircadia.com/vision/) |
| --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| [Yves Hoppe](https://github.com/yvesh) | [durairajasivam](https://github.com/durairajasivam) | [Chris Hayes](https://github.com/Christopher-Hayes) | [Andrew LeTourneau](https://github.com/centerorbit) | [Kalila Lakeworth](https://vircadia.com/vision/) |
| [![Ivorzk](https://avatars2.githubusercontent.com/u/7390138?s=64)](https://github.com/Ivorzk) | [![Eric Schirtzinger](https://avatars2.githubusercontent.com/u/24927782?s=64)](https://github.com/eschirtz) | [![Alec Armbruster](https://avatars2.githubusercontent.com/u/35377827?s=64)](https://github.com/alectrocute) | [![Karim Hossenbux](https://avatars.githubusercontent.com/u/584224?s=64)](https://github.com/karimhossenbux) |
| [Ivorzk](https://github.com/Ivorzk) | [Eric Schirtzinger](https://github.com/eschirtz) | [Alec Armbruster](https://github.com/alectrocute) | [Karim Hossenbux](https://github.com/karimhossenbux) |
| [![Yves Hoppe](https://avatars1.githubusercontent.com/u/897638?s=64&v=4)](https://github.com/yvesh) | [![durairajasivam](https://avatars3.githubusercontent.com/u/6660533?s=64&v=4)](https://github.com/durairajasivam) | [![Alec Armbruster](https://avatars2.githubusercontent.com/u/35377827?s=64)](https://github.com/alectrocute) | [![Tilen Hosnar](https://avatars.githubusercontent.com/u/11992843?s=64)](https://github.com/hosnar) | [![Andrew LeTourneau](https://avatars2.githubusercontent.com/u/2807807?s=64&v=4)](https://github.com/centerorbit) |
| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| [Yves Hoppe](https://github.com/yvesh) | [durairajasivam](https://github.com/durairajasivam) | [Alec Armbruster](https://github.com/alectrocute) | [Tilen Hosnar](https://github.com/hosnar) | [Andrew LeTourneau](https://github.com/centerorbit) |
| [![Kalila Lakeworth](https://avatars1.githubusercontent.com/u/69767640?s=64)](https://vircadia.com/vision/) | [![Eric Schirtzinger](https://avatars2.githubusercontent.com/u/24927782?s=64)](https://github.com/eschirtz) | [![Karim Hossenbux](https://avatars.githubusercontent.com/u/584224?s=64)](https://github.com/karimhossenbux) | [![Decentralized Justice](https://avatars.githubusercontent.com/u/38048901?s=64)](https://github.com/DecentralizeJustice) |
| [Kalila Lakeworth](https://vircadia.com/vision/) | [Eric Schirtzinger](https://github.com/eschirtz) | [Karim Hossenbux](https://github.com/karimhossenbux) | [Decentralized Justice](https://github.com/DecentralizeJustice) |
## Past Supporters
| [<img src="https://avatars2.githubusercontent.com/u/46167401?s=64&v=4" width="64">](https://github.com/Mary-Tyler-Moore) | [![Mitch Dennet](https://avatars2.githubusercontent.com/u/16268619?s=64&v=4)](https://github.com/mitchdennett) |
| ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
| [Mary-Tyler-Moore](https://github.com/Mary-Tyler-Moore) | [Mitch Dennet](https://github.com/mitchdennett) |
| [<img src="https://avatars2.githubusercontent.com/u/46167401?s=64&v=4" width="64">](https://github.com/Mary-Tyler-Moore) | [![Mitch Dennet](https://avatars2.githubusercontent.com/u/16268619?s=64&v=4)](https://github.com/mitchdennett) | [![Chris Hayes](https://avatars3.githubusercontent.com/u/6013871?s=64)](https://github.com/Christopher-Hayes) |
| ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| [Mary-Tyler-Moore](https://github.com/Mary-Tyler-Moore) | [Mitch Dennet](https://github.com/mitchdennett) | [Chris Hayes](https://github.com/Christopher-Hayes) |