UNPKG

22.5 kBJavaScriptView Raw
1const
2 path = require('path'),
3 fs = require('fs'),
4 merge = require('webpack-merge'),
5 chokidar = require('chokidar'),
6 debounce = require('lodash.debounce')
7
8const
9 appPaths = require('./app-paths'),
10 logger = require('./helpers/logger'),
11 log = logger('app:quasar-conf'),
12 warn = logger('app:quasar-conf', 'red'),
13 appFilesValidations = require('./app-files-validations'),
14 extensionRunner = require('./app-extension/extensions-runner')
15
16function encode (obj) {
17 return JSON.stringify(obj, (key, value) => {
18 return typeof value === 'function'
19 ? `/fn(${value.toString()})`
20 : value
21 })
22}
23
24function formatPublicPath (path) {
25 if (!path) {
26 return path
27 }
28
29 if (!path.endsWith('/')) {
30 path = `${path}/`
31 }
32
33 if (path.startsWith('http://') || path.startsWith('https://')) {
34 return path
35 }
36
37 if (!path.startsWith('/')) {
38 path = `/${path}`
39 }
40
41 return path
42}
43
44function formatRouterBase (publicPath) {
45 if (!publicPath || !publicPath.startsWith('http')) {
46 return publicPath
47 }
48
49 const match = publicPath.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/)
50 return formatPublicPath(match[5] || '')
51}
52
53function parseBuildEnv (env) {
54 const obj = {}
55 Object.keys(env).forEach(key => {
56 try {
57 obj[key] = JSON.parse(env[key])
58 }
59 catch (e) {
60 obj[key] = ''
61 }
62 })
63 return obj
64}
65
66function parseAssetProperty (prefix) {
67 return asset => {
68 if (typeof asset === 'string') {
69 return {
70 path: asset[0] === '~' ? asset.substring(1) : prefix + `/${asset}`
71 }
72 }
73
74 return {
75 ...asset,
76 path: typeof asset.path === 'string'
77 ? (asset.path[0] === '~' ? asset.path.substring(1) : prefix + `/${asset.path}`)
78 : asset.path
79 }
80 }
81}
82
83function uniqueFilter (value, index, self) {
84 return self.indexOf(value) === index
85}
86
87function uniquePathFilter (value, index, self) {
88 return self.map(obj => obj.path).indexOf(value.path) === index
89}
90
91function uniqueRegexFilter (value, index, self) {
92 return self.map(regex => regex.toString()).indexOf(value.toString()) === index
93}
94
95/*
96 * this.buildConfig - Compiled Object from quasar.conf.js
97 * this.webpackConfig - Webpack config object for main thread
98 * this.electronWebpackConfig - Webpack config object for electron main thread
99 */
100
101class QuasarConfig {
102 constructor (ctx, opts = {}) {
103 this.ctx = ctx
104 this.opts = opts
105 this.filename = appPaths.resolve.app('quasar.conf.js')
106 this.pkg = require(appPaths.resolve.app('package.json'))
107 this.watch = opts.onBuildChange || opts.onAppChange
108
109 if (this.watch) {
110 // Start watching for quasar.config.js changes
111 chokidar
112 .watch(this.filename, { watchers: { chokidar: { ignoreInitial: true } } })
113 .on('change', debounce(async () => {
114 console.log()
115 log(`quasar.conf.js changed`)
116
117 try {
118 await this.prepare()
119 }
120 catch (e) {
121 if (e.message !== 'NETWORK_ERROR') {
122 console.log(e)
123 warn(`quasar.conf.js has JS errors. Please fix them then save file again.`)
124 warn()
125 }
126
127 return
128 }
129
130 await this.compile()
131
132 if (this.webpackConfigChanged) {
133 opts.onBuildChange()
134 }
135 else {
136 opts.onAppChange()
137 }
138 }, 1000))
139
140 if (this.ctx.mode.ssr) {
141 const SsrExtension = require('./ssr/ssr-extension')
142
143 if (!SsrExtension.isValid()) {
144 process.exit(1)
145 }
146
147 chokidar
148 .watch(appPaths.ssrDir, { watchers: { chokidar: { ignoreInitial: true } } })
149 .on('change', debounce(async () => {
150 console.log()
151 log(`src-ssr/* changed`)
152
153 SsrExtension.deleteCache()
154
155 if (SsrExtension.isValid()) {
156 // trigger build update
157 opts.onBuildChange()
158 }
159 else {
160 warn(`⚠️ [FAIL] Please fix the error then save the file so we can continue.`)
161 }
162 }, 1000))
163 }
164 }
165 }
166
167 // synchronous for build
168 async prepare () {
169 this.readConfig()
170
171 const cfg = merge({
172 ctx: this.ctx,
173 css: [],
174 boot: [],
175 vendor: {
176 add: [],
177 remove: []
178 },
179 build: {
180 transpileDependencies: [],
181 stylusLoaderOptions: {},
182 sassLoaderOptions: {},
183 scssLoaderOptions: {},
184 lessLoaderOptions: {},
185 env: {},
186 uglifyOptions: {
187 compress: {},
188 mangle: {}
189 }
190 },
191 devServer: {},
192 animations: [],
193 extras: [],
194 sourceFiles: {},
195 ssr: {
196 componentCache: {}
197 },
198 pwa: {
199 workboxOptions: {},
200 manifest: {
201 icons: []
202 },
203 metaVariables: {}
204 },
205 electron: {
206 packager: {},
207 builder: {}
208 },
209 cordova: {},
210 htmlVariables: {}
211 }, this.quasarConfigFunction(this.ctx))
212
213 if (cfg.framework === void 0 || cfg.framework === 'all') {
214 cfg.framework = {
215 all: true
216 }
217 }
218 if (!cfg.framework.components) {
219 cfg.framework.components = []
220 }
221 if (!cfg.framework.directives) {
222 cfg.framework.directives = []
223 }
224 if (!cfg.framework.plugins) {
225 cfg.framework.plugins = []
226 }
227 if (!cfg.framework.config) {
228 cfg.framework.config = {}
229 }
230
231 if (this.ctx.dev) {
232 if (this.opts.host) {
233 cfg.devServer.host = this.opts.host
234 }
235 else if (!cfg.devServer.host) {
236 cfg.devServer.host = '0.0.0.0'
237 }
238
239 if (this.opts.port) {
240 cfg.devServer.port = this.opts.port
241 }
242 else if (!cfg.devServer.port) {
243 cfg.devServer.port = 8080
244 }
245
246 if (
247 this.address &&
248 this.address.from.host === cfg.devServer.host &&
249 this.address.from.port === cfg.devServer.port
250 ) {
251 cfg.devServer.host = this.address.to.host
252 cfg.devServer.port = this.address.to.port
253 }
254 else {
255 const addr = {
256 host: cfg.devServer.host,
257 port: cfg.devServer.port
258 }
259 const to = this.opts.onAddress !== void 0
260 ? await this.opts.onAddress(addr)
261 : addr
262
263 // if network error while running
264 if (to === null) {
265 throw new Error('NETWORK_ERROR')
266 }
267
268 cfg.devServer = merge(cfg.devServer, to)
269 this.address = {
270 from: addr,
271 to: {
272 host: cfg.devServer.host,
273 port: cfg.devServer.port
274 }
275 }
276 }
277 }
278
279 this.quasarConfig = cfg
280 }
281
282 getBuildConfig () {
283 return this.buildConfig
284 }
285
286 getWebpackConfig () {
287 return this.webpackConfig
288 }
289
290 readConfig () {
291 log(`Reading quasar.conf.js`)
292
293 if (fs.existsSync(this.filename)) {
294 delete require.cache[this.filename]
295 this.quasarConfigFunction = require(this.filename)
296 }
297 else {
298 warn(`⚠️ [FAIL] Could not load quasar.conf.js config file`)
299 process.exit(1)
300 }
301 }
302
303 async compile () {
304 let cfg = this.quasarConfig
305
306 await extensionRunner.runHook('extendQuasarConf', async hook => {
307 log(`Extension(${hook.api.extId}): Extending quasar.conf...`)
308 await hook.fn(cfg, hook.api)
309 })
310
311 // if watching for changes,
312 // then determine the type (webpack related or not)
313 if (this.watch) {
314 const newConfigSnapshot = [
315 cfg.build ? encode(cfg.build) : '',
316 cfg.ssr ? cfg.ssr.pwa : '',
317 cfg.framework.all,
318 cfg.devServer ? encode(cfg.devServer) : '',
319 cfg.pwa ? encode(cfg.pwa) : '',
320 cfg.electron ? encode(cfg.electron) : ''
321 ].join('')
322
323 if (this.oldConfigSnapshot) {
324 this.webpackConfigChanged = newConfigSnapshot !== this.oldConfigSnapshot
325 }
326
327 this.oldConfigSnapshot = newConfigSnapshot
328 }
329
330 // make sure it exists
331 cfg.supportIE = this.ctx.mode.electron
332 ? false
333 : (cfg.supportIE || false)
334
335 cfg.vendor.add = cfg.vendor.add.filter(v => v).join('|')
336 if (cfg.vendor.add) {
337 cfg.vendor.add = new RegExp(cfg.vendor.add)
338 }
339
340 cfg.vendor.remove = cfg.vendor.remove.filter(v => v).join('|')
341 if (cfg.vendor.remove) {
342 cfg.vendor.remove = new RegExp(cfg.vendor.remove)
343 }
344
345 if (cfg.css.length > 0) {
346 cfg.css = cfg.css.filter(_ => _)
347 .map(parseAssetProperty('src/css'))
348 .filter(asset => asset.path)
349 .filter(uniquePathFilter)
350 }
351
352 if (cfg.boot.length > 0) {
353 cfg.boot = cfg.boot.filter(_ => _)
354 .map(parseAssetProperty('boot'))
355 .filter(asset => asset.path)
356 .filter(uniquePathFilter)
357 }
358
359 if (cfg.extras.length > 0) {
360 cfg.extras = cfg.extras.filter(uniqueFilter)
361 }
362
363 cfg.framework.components = cfg.framework.components.filter(uniqueFilter)
364 cfg.framework.directives = cfg.framework.directives.filter(uniqueFilter)
365 cfg.framework.plugins = cfg.framework.plugins.filter(uniqueFilter)
366
367 cfg.build = merge({
368 showProgress: true,
369 scopeHoisting: true,
370 productName: this.pkg.productName,
371 productDescription: this.pkg.description,
372 extractCSS: this.ctx.prod,
373 sourceMap: this.ctx.dev,
374 minify: this.ctx.prod,
375 distDir: path.join('dist', this.ctx.modeName),
376 htmlFilename: 'index.html',
377 webpackManifest: this.ctx.prod,
378 vueRouterMode: 'hash',
379 preloadChunks: true,
380 // transpileDependencies: [], // leaving here for completeness
381 devtool: this.ctx.dev
382 ? '#cheap-module-eval-source-map'
383 : '#source-map',
384 env: {
385 NODE_ENV: `"${this.ctx.prod ? 'production' : 'development'}"`,
386 CLIENT: true,
387 SERVER: false,
388 DEV: this.ctx.dev,
389 PROD: this.ctx.prod,
390 MODE: `"${this.ctx.modeName}"`
391 },
392 uglifyOptions: {
393 compress: {
394 // turn off flags with small gains to speed up minification
395 arrows: false,
396 collapse_vars: false, // 0.3kb
397 comparisons: false,
398 computed_props: false,
399 hoist_funs: false,
400 hoist_props: false,
401 hoist_vars: false,
402 inline: false,
403 loops: false,
404 negate_iife: false,
405 properties: false,
406 reduce_funcs: false,
407 reduce_vars: false,
408 switches: false,
409 toplevel: false,
410 typeofs: false,
411
412 // a few flags with noticable gains/speed ratio
413 // numbers based on out of the box vendor bundle
414 booleans: true, // 0.7kb
415 if_return: true, // 0.4kb
416 sequences: true, // 0.7kb
417 unused: true, // 2.3kb
418
419 // required features to drop conditional branches
420 conditionals: true,
421 dead_code: true,
422 evaluate: true
423 },
424 mangle: {
425 safari10: true
426 }
427 }
428 }, cfg.build)
429
430 cfg.build.transpileDependencies = cfg.build.transpileDependencies.filter(uniqueRegexFilter)
431
432 cfg.__loadingBar = cfg.framework.all || cfg.framework.plugins.includes('LoadingBar')
433 cfg.__meta = cfg.framework.all || cfg.framework.plugins.includes('Meta')
434
435 if (this.ctx.dev || this.ctx.debug) {
436 Object.assign(cfg.build, {
437 minify: false,
438 gzip: false
439 })
440 }
441 if (this.ctx.dev) {
442 cfg.build.extractCSS = false
443 }
444 if (this.ctx.debug) {
445 cfg.build.sourceMap = true
446 }
447
448 if (this.ctx.mode.ssr) {
449 Object.assign(cfg.build, {
450 extractCSS: false,
451 vueRouterMode: 'history',
452 publicPath: '/',
453 gzip: false
454 })
455 }
456 else if (this.ctx.mode.cordova || this.ctx.mode.electron) {
457 Object.assign(cfg.build, {
458 htmlFilename: 'index.html',
459 vueRouterMode: 'hash',
460 gzip: false,
461 webpackManifest: false
462 })
463 }
464
465 if (this.ctx.mode.cordova) {
466 cfg.build.distDir = appPaths.resolve.app(path.join('src-cordova', 'www'))
467 }
468 else if (!path.isAbsolute(cfg.build.distDir)) {
469 cfg.build.distDir = appPaths.resolve.app(cfg.build.distDir)
470 }
471
472 if (this.ctx.mode.electron) {
473 cfg.build.packagedElectronDist = cfg.build.distDir
474 cfg.build.distDir = path.join(cfg.build.distDir, 'UnPackaged')
475 }
476
477 cfg.build.publicPath =
478 this.ctx.prod && cfg.build.publicPath && ['spa', 'pwa'].includes(this.ctx.modeName)
479 ? formatPublicPath(cfg.build.publicPath)
480 : (cfg.build.vueRouterMode !== 'hash' ? '/' : '')
481
482 cfg.build.vueRouterBase = formatRouterBase(cfg.build.publicPath)
483
484 cfg.build.appBase = cfg.build.vueRouterMode === 'history'
485 ? cfg.build.publicPath
486 : ''
487
488 cfg.sourceFiles = merge({
489 rootComponent: 'src/App.vue',
490 router: 'src/router/index',
491 store: 'src/store/index',
492 indexHtmlTemplate: 'src/index.template.html',
493 registerServiceWorker: 'src-pwa/register-service-worker.js',
494 serviceWorker: 'src-pwa/custom-service-worker.js',
495 electronMainDev: 'src-electron/main-process/electron-main.dev.js',
496 electronMainProd: 'src-electron/main-process/electron-main.js',
497 ssrServerIndex: 'src-ssr/index.js'
498 }, cfg.sourceFiles)
499
500 // do we got vuex?
501 const storePath = appPaths.resolve.app(cfg.sourceFiles.store)
502 cfg.store = (
503 fs.existsSync(storePath) ||
504 fs.existsSync(storePath + '.js') ||
505 fs.existsSync(storePath + '.ts')
506 )
507
508 //make sure we have preFetch in config
509 cfg.preFetch = cfg.preFetch || false
510
511 if (cfg.animations === 'all') {
512 cfg.animations = require('./helpers/animations')
513 }
514
515 if (this.ctx.mode.ssr) {
516 cfg.ssr = merge({
517 pwa: false,
518 componentCache: {
519 max: 1000,
520 maxAge: 1000 * 60 * 15
521 }
522 }, cfg.ssr)
523
524 cfg.ssr.debug = this.ctx.debug
525
526 cfg.ssr.__templateOpts = JSON.stringify(cfg.ssr, null, 2)
527 cfg.ssr.__templateFlags = {
528 meta: cfg.__meta
529 }
530
531 const file = appPaths.resolve.app(cfg.sourceFiles.ssrServerIndex)
532 cfg.ssr.__dir = path.dirname(file)
533 cfg.ssr.__index = path.basename(file)
534
535 if (cfg.ssr.pwa) {
536 require('./mode/install-missing')('pwa')
537 }
538 this.ctx.mode.pwa = cfg.ctx.mode.pwa = cfg.ssr.pwa !== false
539 }
540
541 if (this.ctx.dev) {
542 cfg.devServer = merge({
543 publicPath: cfg.build.publicPath,
544 hot: true,
545 inline: true,
546 overlay: true,
547 quiet: true,
548 historyApiFallback: !this.ctx.mode.ssr,
549 noInfo: true,
550 disableHostCheck: true,
551 compress: true,
552 open: true
553 }, cfg.devServer, {
554 contentBase: [ appPaths.srcDir ]
555 })
556
557 if (this.ctx.mode.ssr) {
558 cfg.devServer.contentBase = false
559 }
560 else if (this.ctx.mode.cordova || this.ctx.mode.electron) {
561 cfg.devServer.open = false
562
563 if (this.ctx.mode.electron) {
564 cfg.devServer.https = false
565 }
566 }
567
568 if (this.ctx.mode.cordova) {
569 cfg.devServer.contentBase.push(
570 appPaths.resolve.cordova(`platforms/${this.ctx.targetName}/platform_www`)
571 )
572 }
573
574 if (cfg.devServer.open) {
575 const isMinimalTerminal = require('./helpers/is-minimal-terminal')
576 if (isMinimalTerminal) {
577 cfg.devServer.open = false
578 }
579 }
580
581 if (cfg.devServer.open) {
582 cfg.__devServer = {
583 open: !!cfg.devServer.open,
584 openOptions: cfg.devServer.open !== true
585 ? cfg.devServer.open
586 : false
587 }
588 cfg.devServer.open = false
589 }
590 else {
591 cfg.__devServer = {}
592 }
593 }
594
595 if (cfg.build.gzip) {
596 let gzip = cfg.build.gzip === true
597 ? {}
598 : cfg.build.gzip
599 let ext = ['js', 'css']
600
601 if (gzip.extensions) {
602 ext = gzip.extensions
603 delete gzip.extensions
604 }
605
606 cfg.build.gzip = merge({
607 filename: '[path].gz[query]',
608 algorithm: 'gzip',
609 test: new RegExp('\\.(' + ext.join('|') + ')$'),
610 threshold: 10240,
611 minRatio: 0.8
612 }, gzip)
613 }
614
615 if (this.ctx.mode.pwa) {
616 cfg.build.webpackManifest = false
617
618 cfg.pwa = merge({
619 workboxPluginMode: 'GenerateSW',
620 workboxOptions: {},
621 manifest: {
622 name: this.pkg.productName || this.pkg.name || 'Quasar App',
623 short_name: this.pkg.name || 'quasar-pwa',
624 description: this.pkg.description,
625 display: 'standalone',
626 start_url: '.'
627 },
628 metaVariables: {
629 appleMobileWebAppCapable: 'yes',
630 appleMobileWebAppStatusBarStyle: 'default',
631 appleTouchIcon120: 'statics/icons/apple-icon-120x120.png',
632 appleTouchIcon180: 'statics/icons/apple-icon-180x180.png',
633 appleTouchIcon152: 'statics/icons/apple-icon-152x152.png',
634 appleTouchIcon167: 'statics/icons/apple-icon-167x167.png',
635 appleSafariPinnedTab: 'statics/icons/safari-pinned-tab.svg',
636 msapplicationTileImage: 'statics/icons/ms-icon-144x144.png',
637 msapplicationTileColor: '#000000'
638 }
639 }, cfg.pwa)
640
641 if (cfg.pwa.manifest.icons.length === 0) {
642 console.log()
643 console.log(`⚠️ PWA manifest in quasar.conf.js > pwa > manifest is missing "icons" prop.`)
644 console.log()
645 process.exit(1)
646 }
647
648 if (!['GenerateSW', 'InjectManifest'].includes(cfg.pwa.workboxPluginMode)) {
649 console.log()
650 console.log(`⚠️ Workbox webpack plugin mode "${cfg.pwa.workboxPluginMode}" is invalid.`)
651 console.log(` Valid Workbox modes are: GenerateSW, InjectManifest`)
652 console.log()
653 process.exit(1)
654 }
655 if (cfg.pwa.cacheExt) {
656 console.log()
657 console.log(`⚠️ Quasar CLI now uses Workbox, so quasar.conf.js > pwa > cacheExt is no longer relevant.`)
658 console.log(` Please remove this property and try again.`)
659 console.log()
660 process.exit(1)
661 }
662 if (
663 fs.existsSync(appPaths.resolve.pwa('service-worker-dev.js')) ||
664 fs.existsSync(appPaths.resolve.pwa('service-worker-prod.js'))
665 ) {
666 console.log()
667 console.log(`⚠️ Quasar CLI now uses Workbox, so src-pwa/service-worker-dev.js and src-pwa/service-worker-prod.js are obsolete.`)
668 console.log(` Please remove and add PWA mode again:`)
669 console.log(` $ quasar mode -r pwa # Warning: this will delete /src-pwa !`)
670 console.log(` $ quasar mode -a pwa`)
671 console.log()
672 process.exit(1)
673 }
674
675 cfg.pwa.manifest.icons = cfg.pwa.manifest.icons.map(icon => {
676 icon.src = `${cfg.build.publicPath}${icon.src}`
677 return icon
678 })
679 }
680
681 if (this.ctx.dev) {
682 const host = cfg.devServer.host === '0.0.0.0'
683 ? 'localhost'
684 : cfg.devServer.host
685 const urlPath = `${cfg.build.vueRouterMode === 'hash' ? (cfg.build.htmlFilename !== 'index.html' ? cfg.build.htmlFilename : '') : ''}`
686 cfg.build.APP_URL = `http${cfg.devServer.https ? 's' : ''}://${host}:${cfg.devServer.port}/${urlPath}`
687 }
688 else if (this.ctx.mode.cordova) {
689 cfg.build.APP_URL = 'index.html'
690 }
691 else if (this.ctx.mode.electron) {
692 cfg.build.APP_URL = `file://" + __dirname + "/index.html`
693 }
694
695 cfg.build.env = merge(cfg.build.env, {
696 VUE_ROUTER_MODE: `"${cfg.build.vueRouterMode}"`,
697 VUE_ROUTER_BASE: `"${cfg.build.vueRouterBase}"`,
698 APP_URL: `"${cfg.build.APP_URL}"`
699 })
700
701 if (this.ctx.mode.pwa) {
702 cfg.build.env.SERVICE_WORKER_FILE = `"${cfg.build.publicPath}service-worker.js"`
703 }
704
705 cfg.build.env = {
706 'process.env': cfg.build.env
707 }
708
709 if (this.ctx.mode.electron) {
710 if (this.ctx.dev) {
711 cfg.build.env.__statics = `"${appPaths.resolve.src('statics').replace(/\\/g, '\\\\')}"`
712 }
713 }
714 else {
715 cfg.build.env.__statics = `"${this.ctx.dev ? '/' : cfg.build.publicPath || '/'}statics"`
716 }
717
718 appFilesValidations(cfg)
719
720 if (this.ctx.mode.electron) {
721 if (this.ctx.prod) {
722 const bundler = require('./electron/bundler')
723
724 cfg.electron = merge({
725 packager: {
726 asar: true,
727 icon: appPaths.resolve.electron('icons/icon'),
728 overwrite: true
729 },
730 builder: {
731 appId: 'quasar-app',
732 productName: this.pkg.productName || this.pkg.name || 'Quasar App',
733 directories: {
734 buildResources: appPaths.resolve.electron('')
735 }
736 }
737 }, cfg.electron, {
738 packager: {
739 dir: cfg.build.distDir,
740 out: cfg.build.packagedElectronDist
741 },
742 builder: {
743 directories: {
744 app: cfg.build.distDir,
745 output: path.join(cfg.build.packagedElectronDist, 'Packaged')
746 }
747 }
748 })
749
750 if (cfg.ctx.bundlerName) {
751 cfg.electron.bundler = cfg.ctx.bundlerName
752 }
753 else if (!cfg.electron.bundler) {
754 cfg.electron.bundler = bundler.getDefaultName()
755 }
756
757 if (cfg.electron.bundler === 'packager') {
758 if (cfg.ctx.targetName) {
759 cfg.electron.packager.platform = cfg.ctx.targetName
760 }
761 if (cfg.ctx.archName) {
762 cfg.electron.packager.arch = cfg.ctx.archName
763 }
764 }
765 else {
766 cfg.electron.builder = {
767 platform: cfg.ctx.targetName,
768 arch: cfg.ctx.archName,
769 config: cfg.electron.builder
770 }
771
772 if (cfg.ctx.publish) {
773 cfg.electron.builder.publish = cfg.ctx.publish
774 }
775
776 bundler.ensureBuilderCompatibility()
777 }
778
779 bundler.ensureInstall(cfg.electron.bundler)
780 }
781 }
782
783 cfg.__html = {
784 variables: {
785 ctx: cfg.ctx,
786 process: {
787 env: parseBuildEnv(cfg.build.env['process.env'])
788 },
789 productName: cfg.build.productName,
790 productDescription: cfg.build.productDescription,
791
792 ...cfg.htmlVariables
793 },
794 minifyOptions: cfg.build.minify
795 ? {
796 removeComments: true,
797 collapseWhitespace: true,
798 removeAttributeQuotes: true
799 // more options:
800 // https://github.com/kangax/html-minifier#options-quick-reference
801 }
802 : undefined
803 }
804
805 this.webpackConfig = await require('./webpack')(cfg)
806 this.buildConfig = cfg
807 }
808}
809
810module.exports = QuasarConfig