Skip to content

Commit

Permalink
feat(app): Allow forcing publicPath on dev mode too (for SPA and PWA …
Browse files Browse the repository at this point in the history
…only) #4962
  • Loading branch information
rstoenescu committed Aug 30, 2019
1 parent 1fb3c59 commit 256e8b8
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 33 deletions.
10 changes: 7 additions & 3 deletions app/lib/dev-server.js
Expand Up @@ -236,8 +236,12 @@ module.exports = class DevServer {

const serverCompilerWatcher = serverCompiler.watch({}, () => {})

const originalAfter = cfg.devServer.after

// start building & launch server
const server = new WebpackDevServer(clientCompiler, {
...cfg.devServer,

after: app => {
if (cfg.ctx.mode.pwa) {
app.use('/manifest.json', (req, res) => {
Expand All @@ -254,6 +258,8 @@ module.exports = class DevServer {
maxAge: 0
}))

originalAfter && originalAfter(app)

SsrExtension.getModule().extendApp({
app,

Expand Down Expand Up @@ -287,9 +293,7 @@ module.exports = class DevServer {
})

app.get('*', render)
},

...cfg.devServer
}
})

readyPromise.then(() => {
Expand Down
57 changes: 31 additions & 26 deletions app/lib/quasar-config.js
Expand Up @@ -24,7 +24,7 @@ function encode (obj) {

function formatPublicPath (path) {
if (!path) {
return path
return path || ''
}

if (!path.endsWith('/')) {
Expand Down Expand Up @@ -477,14 +477,10 @@ class QuasarConfig {
cfg.build.publicPath =
(this.ctx.prod || cfg.build.forceDevPublicPath) && cfg.build.publicPath && ['spa', 'pwa'].includes(this.ctx.modeName)
? formatPublicPath(cfg.build.publicPath)
: (cfg.build.vueRouterMode !== 'hash' ? '/' : '')
: (cfg.build.vueRouterMode === 'hash' ? '' : '/')

cfg.build.vueRouterBase = formatRouterBase(cfg.build.publicPath)

cfg.build.appBase = cfg.build.vueRouterMode === 'history'
? cfg.build.publicPath
: ''

cfg.sourceFiles = merge({
rootComponent: 'src/App.vue',
router: 'src/router/index',
Expand Down Expand Up @@ -539,6 +535,8 @@ class QuasarConfig {
}

if (this.ctx.dev) {
const originalBefore = cfg.devServer.before

cfg.devServer = merge({
publicPath: cfg.build.publicPath,
hot: true,
Expand All @@ -551,26 +549,34 @@ class QuasarConfig {
compress: true,
open: true
}, cfg.devServer, {
contentBase: [ appPaths.srcDir ]
contentBase: false,

before: app => {
if (!this.ctx.mode.ssr) {
const express = require('express')

app.use((cfg.build.publicPath || '/') + 'statics', express.static(appPaths.resolve.src('statics'), {
maxAge: 0
}))

if (this.ctx.mode.cordova) {
const folder = appPaths.resolve.cordova(`platforms/${this.ctx.targetName}/platform_www`)
app.use('/', express.static(folder, { maxAge: 0 }))
}
}

originalBefore && originalBefore(app)
}
})

if (this.ctx.mode.ssr) {
cfg.devServer.contentBase = false
}
else if (this.ctx.mode.cordova || this.ctx.mode.electron) {
if (this.ctx.mode.cordova || this.ctx.mode.electron) {
cfg.devServer.open = false

if (this.ctx.mode.electron) {
cfg.devServer.https = false
}
}

if (this.ctx.mode.cordova) {
cfg.devServer.contentBase.push(
appPaths.resolve.cordova(`platforms/${this.ctx.targetName}/platform_www`)
)
}

if (cfg.devServer.open) {
const isMinimalTerminal = require('./helpers/is-minimal-terminal')
if (isMinimalTerminal) {
Expand Down Expand Up @@ -682,8 +688,12 @@ class QuasarConfig {
const host = cfg.devServer.host === '0.0.0.0'
? 'localhost'
: cfg.devServer.host
const urlPath = `${cfg.build.vueRouterMode === 'hash' ? (cfg.build.htmlFilename !== 'index.html' ? cfg.build.htmlFilename : '') : ''}`
cfg.build.APP_URL = `http${cfg.devServer.https ? 's' : ''}://${host}:${cfg.devServer.port}/${urlPath}`

const urlPath = cfg.build.vueRouterMode === 'hash'
? (cfg.build.htmlFilename !== 'index.html' ? (cfg.build.publicPath ? '' : '/') + cfg.build.htmlFilename : '')
: ''

cfg.build.APP_URL = `http${cfg.devServer.https ? 's' : ''}://${host}:${cfg.devServer.port}${cfg.build.publicPath}${urlPath}`
}
else if (this.ctx.mode.cordova) {
cfg.build.APP_URL = 'index.html'
Expand All @@ -706,13 +716,8 @@ class QuasarConfig {
'process.env': cfg.build.env
}

if (this.ctx.mode.electron) {
if (this.ctx.dev) {
cfg.build.env.__statics = `"${appPaths.resolve.src('statics').replace(/\\/g, '\\\\')}"`
}
}
else {
cfg.build.env.__statics = `"${((this.ctx.prod || cfg.build.forceDevPublicPath) && cfg.build.publicPath) ? cfg.build.publicPath : '/' }statics"`
if (this.ctx.mode.electron && this.ctx.dev) {
cfg.build.env.__statics = `"${appPaths.resolve.src('statics').replace(/\\/g, '\\\\')}"`
}

appFilesValidations(cfg)
Expand Down
4 changes: 2 additions & 2 deletions app/lib/ssr/html-template.js
Expand Up @@ -69,8 +69,8 @@ module.exports.getIndexHtml = function (template, cfg) {

html = injectSsrInterpolation(html)

if (cfg.build.appBase) {
html = fillBaseTag(html, cfg.build.appBase)
if (cfg.build.publicPath) {
html = fillBaseTag(html, cfg.build.publicPath)
}

if (cfg.build.minify) {
Expand Down
4 changes: 2 additions & 2 deletions app/lib/webpack/plugin.html-addons.js
Expand Up @@ -30,9 +30,9 @@ module.exports.plugin = class HtmlAddonsPlugin {

apply (compiler) {
compiler.hooks.compilation.tap('webpack-plugin-html-addons', compilation => {
if (this.cfg.build.appBase) {
if (this.cfg.build.publicPath) {
compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync('webpack-plugin-html-base-tag', (data, callback) => {
data.html = fillBaseTag(data.html, this.cfg.build.appBase)
data.html = fillBaseTag(data.html, this.cfg.build.publicPath)
callback(null, data)
})
}
Expand Down

7 comments on commit 256e8b8

@makaria
Copy link

@makaria makaria commented on 256e8b8 Sep 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, but this commit forced the <base> tag use publicPath as href, which will caused a 'replaceState' error when <base> tag's href is different from app's host and enabled history in vueRouter. This seems to be a bug or missing feature in vue-router. What I expecting is there is no <base> tag in the <header> or the <base> tag's href is '/'. I can't upgrade to v1.0.6 for it will break the compromise methods i'm using now.
You can easily got the router error when assign publicPath as your local ip such as 192.168.0.1:5000 and visit it from localhost:5000 or 127.0.0.1:5000. In addtion, visit from 192.168.0.1:5000 is fine. Unfortunately, i can't visit public.example.com to use the app.

@rstoenescu
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you assigning the publicPath to a full URL? It should only contain the path, not the full URL...

@makaria
Copy link

@makaria makaria commented on 256e8b8 Sep 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally it should, but unfortunately there are some case the publicPath will dynamically change when building and deploying. In my case, I'm using a script like CDN_PATH=http://192.168.0.1:5000/***/ quasar build when building(the *** part will change in each building, normally is a timestamp like string), and the CDN_PATH variable is using as publicPath.
Using publicPath as <base> is all OK except it will throw a replaceState error when enabled history and scrollBehavior in vue-router as shown in ISSUE 2593, which seems has no solution.
Is there anyway to avoid this ? Pardon my poor english.

@rstoenescu
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused about another thing. If you look closely, this commit is just a refactoring while maintaining the same logic (the outcome is the same, just the variables have been "moved" a little). So not sure why commenting on this particular commit actually.

Also, I'd like to understand if you are indeed using publicPath correctly. Are you using it to supply the built js and css files, or for the statics (images, etc)? Cause if it's for the latter, then you're not doing it right...

Also note that Vue Router has its own base (from which "origin" is extracted away). I just have the feeling that you are trying to solve a scenario by wrongly hacking on the publicPath when there should be another way to do it correctly.

Any barebones repo to (reproduce this with) available that I can take a look at? And some basic instructions on how to set it up and run it (as I'm not very familiar with Laravel).

@makaria
Copy link

@makaria makaria commented on 256e8b8 Sep 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your replies, I've create a repo replaceState-error-in-vue-router which can reproduce the replaceState error. In the master branch, I'm using @quasar/app 1.0.6, enabled
history in vueRouteMode and scrollBehavior in routes/index.js, after building and running the quasar serve, open localhost:4000, you'll see the replaceState bug. In the no-bug branch, I'm using @quasar/app 1.0.5, enabled history and scrollBehavior in routes/index.js, there is no error.
Basically it's a vue-router bug, and the unusual deployment, unfortunately, I can't change either of them

@fxjs
Copy link

@fxjs fxjs commented on 256e8b8 Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you assigning the publicPath to a full URL? It should only contain the path, not the full URL...

Because js and image resources are hosted on a third-party cdn and are not in the same domain as index.html, I have the same needs.
Can the base tag restriction be removed?

@eyedean
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fxjs I have the same problem (serving assets from my CDN) and we are discussing it in #4687 (comment) . (Just cross-referencing)

Please sign in to comment.