1
import { join, isAbsolute, basename, dirname, relative } from 'node:path'
2
import { pathToFileURL } from 'node:url'
3
import { existsSync, readFileSync } from 'node:fs'
4
import { createRequire } from 'node:module'
5
import fse from 'fs-extra'
6
import { merge } from 'webpack-merge'
7
import debounce from 'lodash/debounce.js'
8
import { build as esBuild, context as esContextBuild } from 'esbuild'
9
import { transformAssetUrls } from '@quasar/vite-plugin'
11
import { log, warn, fatal, tip } from './utils/logger.js'
12
import { appFilesValidations } from './utils/app-files-validations.js'
13
import { getPackageMajorVersion } from './utils/get-package-major-version.js'
14
import { resolveExtension } from './utils/resolve-extension.js'
15
import { ensureElectronArgv } from './utils/ensure-argv.js'
16
import { quasarEsbuildInjectReplacementsDefine, quasarEsbuildInjectReplacementsPlugin } from './plugins/esbuild.inject-replacements.js'
18
const urlRegex = /^http(s)?:\/\//i
19
import { findClosestOpenPort, localHostList } from './utils/net.js'
20
import { isMinimalTerminal } from './utils/is-minimal-terminal.js'
21
import { readFileEnv } from './utils/env.js'
23
const defaultPortMapping = {
32
const quasarComponentRE = /^(Q[A-Z]|q-)/
33
const quasarConfigBanner = `/* eslint-disable */
35
* THIS FILE IS GENERATED AUTOMATICALLY.
36
* 1. DO NOT edit this file directly as it won't do anything.
37
* 2. EDIT the original quasar.config file INSTEAD.
38
* 3. DO NOT git commit this file. It should be ignored.
40
* This file is still here because there was an error in
41
* the original quasar.config file and this allows you to
42
* investigate the Node.js stack error.
44
* After you fix the original file, this file will be
45
* deleted automatically.
49
function escapeHTMLTagContent (str) {
50
return str ? str.replace(/[<>]/g, '') : ''
52
function escapeHTMLAttribute (str) {
53
return str ? str.replace(/\"/g, '') : ''
56
function formatPublicPath (publicPath) {
61
if (!publicPath.endsWith('/')) {
62
publicPath = `${ publicPath }/`
65
if (urlRegex.test(publicPath) === true) {
69
if (!publicPath.startsWith('/')) {
70
publicPath = `/${ publicPath }`
76
function formatRouterBase (publicPath) {
77
if (!publicPath || !publicPath.startsWith('http')) {
81
const match = publicPath.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/)
82
return formatPublicPath(match[ 5 ] || '')
85
function parseAssetProperty (prefix) {
87
if (typeof asset === 'string') {
89
path: asset[ 0 ] === '~' ? asset.substring(1) : prefix + `/${ asset }`
95
path: typeof asset.path === 'string'
96
? (asset.path[ 0 ] === '~' ? asset.path.substring(1) : prefix + `/${ asset.path }`)
102
function getUniqueArray (original) {
103
return Array.from(new Set(original))
106
function uniquePathFilter (value, index, self) {
107
return self.map(obj => obj.path).indexOf(value.path) === index
110
let cachedExternalHost, addressRunning = false
112
async function onAddress ({ host, port }, mode) {
114
[ 'cordova', 'capacitor' ].includes(mode)
115
&& (!host || localHostList.includes(host.toLowerCase()))
117
if (cachedExternalHost) {
118
host = cachedExternalHost
121
const { getExternalIP } = await import('./utils/get-external-ip.js')
122
host = await getExternalIP()
123
cachedExternalHost = host
128
const openPort = await findClosestOpenPort(port, host)
129
if (port !== openPort) {
131
warn(`️️Setting port to closest one available: ${ openPort }`)
140
if (e.message === 'ERROR_NETWORK_PORT_NOT_AVAIL') {
141
warn('Could not find an open port. Please configure a lower one to start searching with.')
143
else if (e.message === 'ERROR_NETWORK_ADDRESS_NOT_AVAIL') {
144
warn('Invalid host specified. No network address matches. Please specify another one.')
147
warn('Unknown network error occurred')
153
if (addressRunning === false) {
160
addressRunning = true
161
return { host, port }
164
export class QuasarConfigFile {
179
constructor ({ ctx, host, port, verifyAddress, watch }) {
181
this.#opts = { host, port, verifyAddress }
183
if (watch !== void 0) {
184
this.#opts.watch = debounce(watch, 550)
187
const { appPaths } = ctx
189
this.#require = appPaths.quasarConfigOutputFormat === 'cjs'
190
? createRequire(import.meta.url)
193
const quasarConfigFileExtension = appPaths.quasarConfigOutputFormat === 'esm' ? 'mjs' : appPaths.quasarConfigOutputFormat
196
this.#tempFile = `${ appPaths.quasarConfigFilename }.temporary.compiled.${ Date.now() }.${ quasarConfigFileExtension }`
198
log(`Using ${ basename(appPaths.quasarConfigFilename) } in "${ appPaths.quasarConfigInputFormat }" format`)
202
const { appPaths, cacheProxy, appExt } = this.#ctx
204
this.#cssVariables = await cacheProxy.getModule('cssVariables')
205
this.#storeProvider = await cacheProxy.getModule('storeProvider')
207
await appExt.registerAppExtensions()
209
if (this.#ctx.mode.pwa) {
213
else if (this.#ctx.mode.capacitor) {
214
const { capVersion } = await cacheProxy.getModule('capCli')
216
const getCapPluginVersion = capVersion <= 2
219
const version = getPackageMajorVersion(name, appPaths.capacitorDir)
220
return version === void 0
225
Object.assign(this.#versions, {
226
capacitor: capVersion,
227
capacitorPluginApp: getCapPluginVersion('@capacitor/app'),
228
capacitorPluginSplashscreen: getCapPluginVersion('@capacitor/splash-screen')
234
const esbuildConfig = this.#createEsbuildConfig()
235
return this.#opts.watch !== void 0
236
? this.#buildAndWatch(esbuildConfig)
237
: this.#build(esbuildConfig)
242
this.#isWatching = true
245
#createEsbuildConfig () {
246
const { appPaths } = this.#ctx
250
format: appPaths.quasarConfigOutputFormat,
252
packages: 'external',
254
'quasar/wrappers': appPaths.quasarConfigOutputFormat === 'esm' ? 'quasar/wrappers/index.mjs' : 'quasar/wrappers/index.js'
257
js: quasarConfigBanner
259
define: quasarEsbuildInjectReplacementsDefine,
260
resolveExtensions: [ appPaths.quasarConfigOutputFormat === 'esm' ? '.mjs' : '.cjs', '.js', '.mts', '.ts', '.json' ],
261
entryPoints: [ appPaths.quasarConfigFilename ],
262
outfile: this.#tempFile,
263
plugins: [ quasarEsbuildInjectReplacementsPlugin ]
267
async #build (esbuildConfig) {
269
await esBuild(esbuildConfig)
272
fse.removeSync(this.#tempFile)
275
fatal('Could not compile the quasar.config file because it has errors.', 'FAIL')
280
const fnResult = await import(
281
pathToFileURL(this.#tempFile)
284
quasarConfigFn = fnResult.default || fnResult
290
'The quasar.config file has runtime errors. Please check the Node.js stack above against the'
291
+ ` temporarily created ${ basename(this.#tempFile) } file, fix the original file`
292
+ ' then DELETE the temporary one ("quasar clean --qconf" can be used).',
297
return this.#computeConfig(quasarConfigFn, true)
300
async #buildAndWatch (esbuildConfig) {
303
const { appPaths } = this.#ctx
304
const { updateAppPackageJson } = this.#ctx.pkg
305
const tempFile = this.#tempFile
307
esbuildConfig.plugins.push({
308
name: 'quasar:watcher',
312
build.onStart(() => {
313
if (isFirst === false) {
315
log('The quasar.config file (or its dependencies) changed. Reading it again...')
316
updateAppPackageJson()
320
build.onEnd(async result => {
321
if (isFirst === false && this.#isWatching === false) {
326
if (result.errors.length !== 0) {
327
fse.removeSync(tempFile)
329
const msg = 'Could not compile the quasar.config file because it has errors.'
331
if (isFirst === true) {
335
warn(msg + ' Please fix them.\n')
342
if (appPaths.quasarConfigOutputFormat === 'cjs') {
343
delete this.#require.cache[ tempFile ]
347
const result = appPaths.quasarConfigOutputFormat === 'esm'
348
? await import(pathToFileURL(tempFile) + '?t=' + Date.now())
349
: this.#require(tempFile)
351
quasarConfigFn = result.default || result
355
if (appPaths.quasarConfigOutputFormat === 'cjs') {
356
delete this.#require.cache[ tempFile ]
362
const msg = 'Importing quasar.config file results in error. Please check the'
363
+ ` Node.js stack above against the temporarily created ${ basename(tempFile) } file`
364
+ ' and fix the original file then DELETE the temporary one ("quasar clean --qconf" can be used).'
366
if (isFirst === true) {
375
if (appPaths.quasarConfigOutputFormat === 'cjs') {
376
delete this.#require.cache[ tempFile ]
379
const quasarConf = await this.#computeConfig(quasarConfigFn, isFirst)
381
if (quasarConf === void 0) {
385
if (isFirst === true) {
387
firstBuildIsDone(quasarConf)
391
log('Scheduled to apply quasar.config changes in 550ms')
392
this.#opts.watch(quasarConf)
397
const esbuildCtx = await esContextBuild(esbuildConfig)
398
await esbuildCtx.watch()
400
return new Promise(res => {
401
firstBuildIsDone = res
407
async #computeConfig (quasarConfigFn, failOnError) {
408
if (typeof quasarConfigFn !== 'function') {
409
fse.removeSync(this.#tempFile)
411
const msg = 'The default export value of the quasar.config file is not a function.'
413
if (failOnError === true) {
417
warn(msg + ' Please fix it.\n')
424
userCfg = await quasarConfigFn(this.#ctx)
430
const msg = 'The quasar.config file has runtime errors.'
431
+ ' Please check the Node.js stack above against the'
432
+ ` temporarily created ${ basename(this.#tempFile) } file`
433
+ ' then DELETE it ("quasar clean --qconf" can be used).'
435
if (failOnError === true) {
439
warn(msg + ' Please fix the errors in the original file.\n')
443
if (Object(userCfg) !== userCfg) {
444
fse.removeSync(this.#tempFile)
446
const msg = 'The quasar.config file does not default exports an Object.'
448
if (failOnError === true) {
452
warn(msg + ' Please fix it.\n')
456
fse.removeSync(this.#tempFile)
458
const { appPaths } = this.#ctx
460
const rawQuasarConf = merge({
485
viteVuePluginOptions: {},
491
htmlMinifyOptions: {}
500
unPackagedInstallParams: [],
506
capacitorCliPreparationParams: []
514
debugging: this.#ctx.dev === true || this.#ctx.debug === true,
515
needsAppMountHook: false,
517
versions: { ...this.#versions },
518
css: { ...this.#cssVariables }
521
if (rawQuasarConf.animations === 'all') {
522
rawQuasarConf.animations = await this.#ctx.cacheProxy.getModule('animations')
526
await this.#ctx.appExt.runAppExtensionHook('extendQuasarConf', async hook => {
527
log(`Extension(${ hook.api.extId }): Extending quasar.config file configuration...`)
528
await hook.fn(rawQuasarConf, hook.api)
535
if (failOnError === true) {
536
fatal('One of your installed App Extensions failed to run', 'FAIL')
539
warn('One of your installed App Extensions failed to run.\n')
549
if (this.#ctx.mode.ssr) {
552
pwaOfflineHtmlFilename: 'offline.html',
553
manualStoreHydration: false,
554
manualPostHydrationTrigger: false,
560
if (this.#ctx.dev && this.#ctx.mode.bex !== true) {
561
if (this.#opts.host) {
562
cfg.devServer.host = this.#opts.host
564
else if (!cfg.devServer.host) {
565
cfg.devServer.host = '0.0.0.0'
568
if (this.#opts.port) {
569
cfg.devServer.port = this.#opts.port
570
tip('You are using the --port parameter. It is recommended to use a different devServer port for each Quasar mode to avoid browser cache issues')
572
else if (!cfg.devServer.port) {
573
cfg.devServer.port = defaultPortMapping[ this.#ctx.modeName ]
574
+ (this.#ctx.mode.ssr === true && cfg.ssr.pwa === true ? 50 : 0)
578
'You (or an AE) specified an explicit quasar.config file > devServer > port. It is recommended to use'
579
+ ' a different devServer > port for each Quasar mode to avoid browser cache issues.'
580
+ ' Example: ctx.mode.ssr ? 9100 : ...'
586
&& this.#address.from.host === cfg.devServer.host
587
&& this.#address.from.port === cfg.devServer.port
589
cfg.devServer.host = this.#address.to.host
590
cfg.devServer.port = this.#address.to.port
594
host: cfg.devServer.host,
595
port: cfg.devServer.port
597
const to = this.#opts.verifyAddress === true
598
? await onAddress(addr, this.#ctx.modeName)
603
const msg = 'Network error encountered while following the quasar.config file host/port config.'
605
if (failOnError === true) {
609
warn(msg + ' Reconfigure and save the file again.\n')
613
cfg.devServer = merge({ open: true }, cfg.devServer, to)
617
host: cfg.devServer.host,
618
port: cfg.devServer.port
624
if (cfg.css.length > 0) {
625
cfg.css = cfg.css.filter(_ => _)
626
.map(parseAssetProperty('src/css'))
627
.filter(asset => asset.path)
628
.filter(uniquePathFilter)
631
if (cfg.boot.length > 0) {
632
cfg.boot = cfg.boot.filter(_ => _)
633
.map(parseAssetProperty('boot'))
634
.filter(asset => asset.path)
635
.filter(uniquePathFilter)
638
if (cfg.extras.length > 0) {
639
cfg.extras = getUniqueArray(cfg.extras)
642
if (cfg.animations.length > 0) {
643
cfg.animations = getUniqueArray(cfg.animations)
646
if (![ 'kebab', 'pascal', 'combined' ].includes(cfg.framework.autoImportComponentCase)) {
647
cfg.framework.autoImportComponentCase = 'kebab'
651
const { config } = cfg.framework
653
if (config.loading) {
654
const { spinner } = config.loading
655
if (quasarComponentRE.test(spinner)) {
656
cfg.framework.components.push(spinner)
661
const { spinner } = config.notify
662
if (quasarComponentRE.test(spinner)) {
663
cfg.framework.components.push(spinner)
667
cfg.framework.components = getUniqueArray(cfg.framework.components)
668
cfg.framework.directives = getUniqueArray(cfg.framework.directives)
669
cfg.framework.plugins = getUniqueArray(cfg.framework.plugins)
671
Object.assign(cfg.metaConf, {
672
packageTypeBasedExtension: this.#ctx.pkg.appPkg.type === 'module' ? 'js' : 'mjs',
673
hasLoadingBarPlugin: cfg.framework.plugins.includes('LoadingBar'),
674
hasMetaPlugin: cfg.framework.plugins.includes('Meta')
678
viteVuePluginOptions: {
679
isProduction: this.#ctx.prod === true,
681
isProd: this.#ctx.prod === true,
686
vueRouterMode: 'hash',
688
minify: cfg.metaConf.debugging !== true
689
&& (this.#ctx.mode.bex !== true || cfg.bex.minify === true),
691
sourcemap: cfg.metaConf.debugging === true,
693
useFilenameHashes: true,
694
polyfillModulePreload: false,
695
distDir: join('dist', this.#ctx.modeName),
698
removeComments: true,
699
collapseWhitespace: true,
700
removeAttributeQuotes: true,
701
collapseBooleanAttributes: true,
702
removeScriptTypeAttributes: true
709
__VUE_OPTIONS_API__: cfg.build.vueOptionsAPI !== false,
710
__VUE_PROD_DEVTOOLS__: cfg.metaConf.debugging,
711
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: cfg.metaConf.debugging,
714
__VUE_I18N_FULL_INSTALL__: true,
715
__VUE_I18N_LEGACY_API__: true,
716
__VUE_I18N_PROD_DEVTOOLS__: cfg.metaConf.debugging,
717
__INTLIFY_PROD_DEVTOOLS__: cfg.metaConf.debugging
721
src: appPaths.srcDir,
722
app: appPaths.appDir,
723
components: appPaths.resolve.src('components'),
724
layouts: appPaths.resolve.src('layouts'),
725
pages: appPaths.resolve.src('pages'),
726
assets: appPaths.resolve.src('assets'),
727
boot: appPaths.resolve.src('boot'),
728
stores: appPaths.resolve.src('stores')
732
if (!cfg.build.target.browser) {
733
cfg.build.target.browser = [ 'es2022', 'firefox115', 'chrome115', 'safari14' ]
736
if (!cfg.build.target.node) {
737
cfg.build.target.node = 'node18'
740
if (this.#ctx.mode.ssr) {
741
cfg.build.vueRouterMode = 'history'
743
else if (this.#ctx.mode.cordova || this.#ctx.mode.capacitor || this.#ctx.mode.electron || this.#ctx.mode.bex) {
744
cfg.build.vueRouterMode = 'hash'
747
if (this.#ctx.dev === true && this.#ctx.mode.bex) {
753
const name = basename(cfg.build.distDir)
755
cfg.build.distDir = join(
756
dirname(cfg.build.distDir),
757
name === 'bex' ? 'bex--dev' : `bex-dev--${ name }`
761
if (!isAbsolute(cfg.build.distDir)) {
762
cfg.build.distDir = appPaths.resolve.app(cfg.build.distDir)
766
= cfg.build.publicPath && [ 'spa', 'pwa', 'ssr' ].includes(this.#ctx.modeName)
767
? formatPublicPath(cfg.build.publicPath)
768
: ([ 'capacitor', 'cordova', 'electron', 'bex' ].includes(this.#ctx.modeName) ? '' : '/')
771
cfg.build.vueRouterBase = cfg.build.vueRouterBase !== void 0
772
? cfg.build.vueRouterBase
773
: formatRouterBase(cfg.build.publicPath)
777
cfg.sourceFiles = merge({
778
rootComponent: 'src/App.vue',
779
router: 'src/router/index',
780
store: `src/${ this.#storeProvider.pathKey }/index`,
781
pwaRegisterServiceWorker: 'src-pwa/register-service-worker',
782
pwaServiceWorker: 'src-pwa/custom-service-worker',
783
pwaManifestFile: 'src-pwa/manifest.json',
784
electronMain: 'src-electron/electron-main',
785
bexManifestFile: 'src-bex/manifest.json'
788
if (appFilesValidations(appPaths) === false) {
789
if (failOnError === true) {
790
fatal('Files validation not passed successfully', 'FAIL')
793
warn('Files validation not passed successfully. Please fix the issues.\n')
798
const storePath = appPaths.resolve.app(cfg.sourceFiles.store)
799
Object.assign(cfg.metaConf, {
800
hasStore: resolveExtension(storePath) !== void 0,
801
storePackage: this.#storeProvider.name
805
cfg.preFetch = cfg.preFetch || false
807
if (this.#ctx.mode.capacitor & cfg.capacitor.capacitorCliPreparationParams.length === 0) {
808
cfg.capacitor.capacitorCliPreparationParams = [ 'sync', this.#ctx.targetName ]
812
if (cfg.devServer.https === true) {
813
const { getCertificate } = await import('@quasar/ssl-certificate')
814
const sslCertificate = getCertificate({ log, fatal })
815
cfg.devServer.https = {
820
else if (Object(cfg.devServer.https) === cfg.devServer.https) {
821
const { https } = cfg.devServer
826
;[ 'ca', 'pfx', 'key', 'cert' ].forEach(prop => {
827
if (typeof https[ prop ] === 'string') {
829
https[ prop ] = readFileSync(https[ prop ])
835
warn(`The devServer.https.${ prop } file could not be read. Removed the config.`)
842
if (this.#ctx.mode.ssr) {
843
if (cfg.ssr.manualPostHydrationTrigger !== true) {
844
cfg.metaConf.needsAppMountHook = true
847
if (cfg.ssr.middlewares.length > 0) {
848
cfg.ssr.middlewares = cfg.ssr.middlewares.filter(_ => _)
849
.map(parseAssetProperty('app/src-ssr/middlewares'))
850
.filter(asset => asset.path)
851
.filter(uniquePathFilter)
854
if (cfg.ssr.pwa === true) {
856
const { addMode } = await import('../lib/modes/pwa/pwa-installation.js')
857
await addMode({ ctx: this.#ctx, silent: true })
860
this.#ctx.mode.pwa = cfg.ctx.mode.pwa = cfg.ssr.pwa === true
864
if (this.#ctx.vueDevtools === true || cfg.devServer.vueDevtools === true) {
865
if (this.#vueDevtools === void 0) {
866
const host = localHostList.includes(cfg.devServer.host.toLowerCase())
870
this.#vueDevtools = {
872
port: await findClosestOpenPort(11111, '0.0.0.0')
876
cfg.metaConf.vueDevtools = { ...this.#vueDevtools }
879
if (this.#ctx.mode.cordova || this.#ctx.mode.capacitor || this.#ctx.mode.electron) {
880
if (this.#ctx.mode.electron) {
881
cfg.devServer.https = false
884
else if (cfg.devServer.open) {
885
cfg.metaConf.openBrowser = !isMinimalTerminal
890
delete cfg.devServer.open
893
if (this.#ctx.mode.pwa) {
895
workboxMode: 'GenerateSW',
896
injectPwaMetaTags: true,
898
manifestFilename: 'manifest.json',
899
useCredentialsForManifestTag: false
902
if (![ 'GenerateSW', 'InjectManifest' ].includes(cfg.pwa.workboxMode)) {
903
const msg = `Workbox strategy "${ cfg.pwa.workboxMode }" is invalid. `
904
+ 'Valid quasar.config file > pwa > workboxMode options are: GenerateSW or InjectManifest.'
906
if (failOnError === true) {
910
warn(msg + ' Please fix it.\n')
914
cfg.build.env.SERVICE_WORKER_FILE = `${ cfg.build.publicPath }${ cfg.pwa.swFilename }`
915
cfg.metaConf.pwaManifestFile = appPaths.resolve.app(cfg.sourceFiles.pwaManifestFile)
918
const swPath = appPaths.resolve.app(cfg.sourceFiles.pwaServiceWorker)
919
cfg.sourceFiles.pwaServiceWorker = resolveExtension(swPath) || cfg.sourceFiles.pwaServiceWorker
921
else if (this.#ctx.mode.bex) {
922
cfg.metaConf.bexManifestFile = appPaths.resolve.app(cfg.sourceFiles.bexManifestFile)
926
const getUrl = hostname => `http${ cfg.devServer.https ? 's' : '' }://${ hostname }:${ cfg.devServer.port }${ cfg.build.publicPath }`
927
const hostname = cfg.devServer.host === '0.0.0.0'
931
cfg.metaConf.APP_URL = getUrl(hostname)
932
cfg.metaConf.getUrl = getUrl
934
else if (this.#ctx.mode.cordova || this.#ctx.mode.capacitor || this.#ctx.mode.bex) {
935
cfg.metaConf.APP_URL = 'index.html'
938
Object.assign(cfg.build.env, {
939
NODE_ENV: this.#ctx.prod ? 'production' : 'development',
942
DEV: this.#ctx.dev === true,
943
PROD: this.#ctx.prod === true,
944
DEBUGGING: cfg.metaConf.debugging === true,
945
MODE: this.#ctx.modeName,
946
VUE_ROUTER_MODE: cfg.build.vueRouterMode,
947
VUE_ROUTER_BASE: cfg.build.vueRouterBase
950
if (cfg.metaConf.APP_URL) {
951
cfg.build.env.APP_URL = cfg.metaConf.APP_URL
955
const { fileEnv, usedEnvFiles, envFromCache } = readFileEnv({
960
cfg.metaConf.fileEnv = fileEnv
962
if (envFromCache === false && usedEnvFiles.length !== 0) {
963
log(`Using .env files: ${ usedEnvFiles.join(', ') }`)
966
if (this.#ctx.mode.electron) {
967
if (!userCfg.electron?.preloadScripts) {
968
cfg.electron.preloadScripts = [ 'electron-preload' ]
972
if (this.#electronInspectPort === void 0) {
973
this.#electronInspectPort = await findClosestOpenPort(userCfg.electron?.inspectPort || 5858, '127.0.0.1')
976
cfg.electron.inspectPort = this.#electronInspectPort
979
const { ensureInstall, getDefaultName } = await this.#ctx.cacheProxy.getModule('electron')
981
const icon = appPaths.resolve.electron('icons/icon.png')
982
const builderIcon = process.platform === 'linux'
984
? (existsSync(icon) === true ? icon : appPaths.resolve.electron('icons/linux-512x512.png'))
985
: appPaths.resolve.electron('icons/icon')
987
cfg.electron = merge({
990
icon: appPaths.resolve.electron('icons/icon'),
996
productName: this.#ctx.pkg.appPkg.productName || this.#ctx.pkg.appPkg.name || 'Quasar App',
998
buildResources: appPaths.resolve.electron('')
1003
dir: join(cfg.build.distDir, 'UnPackaged'),
1004
out: join(cfg.build.distDir, 'Packaged')
1008
app: join(cfg.build.distDir, 'UnPackaged'),
1009
output: join(cfg.build.distDir, 'Packaged')
1014
if (cfg.ctx.bundlerName) {
1015
cfg.electron.bundler = cfg.ctx.bundlerName
1017
else if (!cfg.electron.bundler) {
1018
cfg.electron.bundler = getDefaultName()
1021
ensureElectronArgv(cfg.electron.bundler, this.#ctx)
1023
if (cfg.electron.bundler === 'packager') {
1024
if (cfg.ctx.targetName) {
1025
cfg.electron.packager.platform = cfg.ctx.targetName
1027
if (cfg.ctx.archName) {
1028
cfg.electron.packager.arch = cfg.ctx.archName
1032
cfg.electron.builder = {
1033
config: cfg.electron.builder
1036
if (cfg.ctx.targetName === 'mac' || cfg.ctx.targetName === 'darwin' || cfg.ctx.targetName === 'all') {
1037
cfg.electron.builder.mac = []
1040
if (cfg.ctx.targetName === 'linux' || cfg.ctx.targetName === 'all') {
1041
cfg.electron.builder.linux = []
1044
if (cfg.ctx.targetName === 'win' || cfg.ctx.targetName === 'win32' || cfg.ctx.targetName === 'all') {
1045
cfg.electron.builder.win = []
1048
if (cfg.ctx.archName) {
1049
cfg.electron.builder[ cfg.ctx.archName ] = true
1052
if (cfg.ctx.publish) {
1053
cfg.electron.builder.publish = cfg.ctx.publish
1057
ensureInstall(cfg.electron.bundler)
1061
const entryScriptWebPath = relative(appPaths.appDir, appPaths.resolve.entry('client-entry.js')).replaceAll('\\', '/')
1062
Object.assign(cfg.metaConf, {
1063
entryScriptWebPath: cfg.build.publicPath + entryScriptWebPath,
1065
entryScriptTag: `<script type="module" src="/${ entryScriptWebPath }"></script>`
1068
cfg.htmlVariables = merge({
1070
process: { env: cfg.build.env },
1071
productName: escapeHTMLTagContent(this.#ctx.pkg.appPkg.productName),
1072
productDescription: escapeHTMLAttribute(this.#ctx.pkg.appPkg.description)
1073
}, cfg.htmlVariables)
1075
if (this.#ctx.mode.capacitor && cfg.metaConf.versions.capacitorPluginSplashscreen && cfg.capacitor.hideSplashscreen !== false) {
1076
cfg.metaConf.needsAppMountHook = true