1 | const
|
2 | path = require('path'),
|
3 | fs = require('fs'),
|
4 | merge = require('webpack-merge'),
|
5 | chokidar = require('chokidar'),
|
6 | debounce = require('lodash.debounce')
|
7 |
|
8 | const
|
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 |
|
16 | function encode (obj) {
|
17 | return JSON.stringify(obj, (key, value) => {
|
18 | return typeof value === 'function'
|
19 | ? `/fn(${value.toString()})`
|
20 | : value
|
21 | })
|
22 | }
|
23 |
|
24 | function 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 |
|
44 | function 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 |
|
53 | function 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 |
|
66 | function 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 |
|
83 | function uniqueFilter (value, index, self) {
|
84 | return self.indexOf(value) === index
|
85 | }
|
86 |
|
87 | function uniquePathFilter (value, index, self) {
|
88 | return self.map(obj => obj.path).indexOf(value.path) === index
|
89 | }
|
90 |
|
91 | function uniqueRegexFilter (value, index, self) {
|
92 | return self.map(regex => regex.toString()).indexOf(value.toString()) === index
|
93 | }
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 | class 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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
312 |
|
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 |
|
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 |
|
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 |
|
395 | arrows: false,
|
396 | collapse_vars: false,
|
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 |
|
413 |
|
414 | booleans: true,
|
415 | if_return: true,
|
416 | sequences: true,
|
417 | unused: true,
|
418 |
|
419 |
|
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 |
|
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 |
|
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 |
|
800 |
|
801 | }
|
802 | : undefined
|
803 | }
|
804 |
|
805 | this.webpackConfig = await require('./webpack')(cfg)
|
806 | this.buildConfig = cfg
|
807 | }
|
808 | }
|
809 |
|
810 | module.exports = QuasarConfig
|