Preact-cli: homepage path for production builds

Created on 12 Jul 2017  路  9Comments  路  Source: preactjs/preact-cli

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.

help wanted

Most helpful comment

@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.

All 9 comments

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:

  1. Allow the user to set the public path through a config variable of some kind (e.g. a homepage variable in package.json as described in #270).
  2. Set Webpack's output.publicUrl to be the value of that variable (more specifically, env.pkg.homepage || '/')
  3. Define a new constant (e.g. 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.)
  4. In 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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yoshiwarab picture yoshiwarab  路  3Comments

haggen picture haggen  路  3Comments

scottmas picture scottmas  路  3Comments

smjnab picture smjnab  路  3Comments

hardcoar picture hardcoar  路  3Comments