It would be better if we can ask the user to add a homepage url/public url which we can use for providing a path for service workers.
Do you mean for loading in a subdirectory? Usually serviceworkers are just loaded via /sw.js.
IIRC a service worker loaded from a specific folder cannot control its parent routes
@developit But if the entire app is being hosted under a subdirectory example.com/app (in my particular case, /app is a virtual directory in Azure), then the path for the service worker needs to /app/sw.js. Otherwise the browser will try to load the service worker from /sw.js and get a 404. Changing Webpack's publicPath to /app/ does the trick for bundles and static assets, but the service worker location is hardcoded. The only way I can get around this at present is to manually modify entry.js.
I'm not sure why I closed this. Reopening
As far as I can see, making this work will require the following:
homepage variable in package.json as described in #270).output.publicUrl to be the value of that variable (more specifically, env.pkg.homepage || '/')process.env.HOMEPAGE) to allow entry.js to appropriately prefix the path to the service worker. (Conveniently, this would also let users make use of the variable in their own code for special redirects, router basename configs, etc.)template.html, make sure manifest.json also gets prefixed with the homepage path.One issue that remains is that paths to static assets defined in configuration files (like icon paths in the manifest) will _not_ get prefixed, and the user must remember to prefix them manually. One way to make this easier might be to make the manifest a template file in which you could use the public path as a template variable.
Would love to hear anyone's thoughts on this.
@reznord
Given there's access to the WebPack config already and you can pass in a template can this all be done with the publicPath from WebPack?
Maybe using env.ASSETS for public assets?
preact.config.js
export default function (config, env, helpers) {
/** you can change config here **/
env.ASSETS = "/app/assets/";
if(env.production){
config.output.publicPath = "/app/";
}
}
template excerpt
<link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath %> manifest.json">
<% if (htmlWebpackPlugin.options.manifest.theme_color) { %>
<meta name="theme-color" content="<%= htmlWebpackPlugin.options.manifest.theme_color %>">
<% } %>
<% for (var chunk of webpack.chunks) { %>
<% if (chunk.names.length === 1 && chunk.names[0] === 'polyfills') continue; %>
<% for (var file of chunk.files) { %>
<% if (htmlWebpackPlugin.options.preload && file.match(/\.(js|css)$/)) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.publicPath + file %>" as="<%= file.match(/\.css$/)?'style':'script' %>">
<% } else if (file.match(htmlWebpackPlugin.files.publicPath + /manifest\.json$/)) { %>
<link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath + file %>">
<% } %>
<% } %>
<% } %>
@timarney Unfortunately this solution will not take care of the service worker path, which will still be /sw.js.
@ethanroday right thanks was just looking at your PR (entry.js).
Something else I ran into while trying to get this to work is paths in css files. Might be a bit of an edge case but I have some global .scss files I'm pulling in (existing / legacy stuff). I ended up using a SASS variable - background: url("#{$assetPath}images/Arrow.png") . Not sure if this could be handled somehow the Sass var doesn't account for dev VS prod env.
... would also let users make use of the variable in their own code for special redirects, router basename configs, etc.
Also seeing making a variable available to "the app code" as you mentioned would be valuable.
Thanks for your work on this.
I addressed a possible /sw.js solution in https://github.com/developit/preact-cli/pull/315#issuecomment-323490486.
@timarney I'm pretty sure you want the custom options.publicPath from the ExtractText plugin. My personal rule of thumb is to always write css urls with an absolute path in mind.
Most helpful comment
@developit But if the entire app is being hosted under a subdirectory
example.com/app(in my particular case,/appis a virtual directory in Azure), then the path for the service worker needs to/app/sw.js. Otherwise the browser will try to load the service worker from/sw.jsand get a 404. Changing Webpack'spublicPathto/app/does the trick for bundles and static assets, but the service worker location is hardcoded. The only way I can get around this at present is to manually modifyentry.js.