I am trying to work out how to enable compression on static content. I have a method similar to
http://romikoderbynew.com/2014/09/04/nancy-rest-services-gzip-it/
When you add a line like below to the ConfigureConventions in the bootstrap
nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("Content", #"Content")); and wire up a the compression code to pipelines.AfterRequest, any static content does not seem to go through the after request hook.
Is there anyway the static content can go through the pipeline so I can decide if i want to compress?
Static content doesn't go through the pipeline. You'll have to replace the "Content" convention handler with your own that does compression.
If there are only a handful of files, you can place them in a different folder and handle them in a separate module using standard Nancy routing. Then it will go through your pipeline handlers.
Related
I currently have an existing Preact JS site set up but want to add blog section.
So basically easy way to add new pages and routes.
I.e. blog/content-1, blog/content-2
I know I could easily create these pages and routes manually but is there something better out there that fits into existing sites ?
I.e. a lot of the static site generators I see out there, basically you need to run from the start and they generate a new site.
But in my case I just wish to add an extra section to my site which will be the static blog entries, not sure what the best tools out there for this is ?
If any ideas or suggestions would be great.
The preactjs.com website is built exactly how you are wanting to build this. It's open source: https://github.com/developit/preact-www
Basically, fetch your HTML content via Ajax (however you'd like), then render.it as Virtual DOM using preact-markup.
For a real-world example, here's how preactjs.com does that:
https://github.com/developit/preact-www/blob/master/src/components/content-region.js
What is the best approach/ strategy to implementing Accelerated Mobile Pages (https://www.ampproject.org/) within AEM 6.1 for a responsive web site that already renders for both desktop and mobile?
An initial concern is that you would be creating duplicate pages of content. So is it possible that AMP and normal html can share the same content?
Would you always redirect to AMP if mobile, and what is the best way to do that?
How would an author handle both AMP and standard pages?
More information is required to completely answer your question -
What is your approach towards responsive design (if you are supporting desktop)? Are mobile site and desktop site different?
What version of AEM are you using?
How would an author handle both AMP and standard pages?
Authoring is something which is not AMP specific, AMP is a feature/behavior that you would enforce on Publish instance and not Author. But this depends on your approach towards responsive behavior - single site handing both mobile and desktop or separate?
a) If there are separate sites then you would actually cater to AMP behavior on author as well by having different components/resource types and page templates for it (This is how prior to AEM 5.6 mobile sites were handled). I can provide more details if you are following this approach
b) If there is single site then you should configure this at publish only.
is it possible that AMP and normal html can share the same content?
In short Yes, depends on how you design your components and/or what version of AEM are you using. In AEM 6.2, Adobe has introduced content fragments that allows channel agnostic content management i.e. more like assets.
If you are not using AEM 6.2, even then you can allow for reusable content by designing for it. You could create a global space with content pieces and then use reference component to associate/use that content on different pages (the only challenge with this is to manage full text search if you have that on your site).
Would you always redirect to AMP if mobile, and what is the best way
to do that?
What ever approach you take a) or b) (as described in first answer), the essence for managing the redirects/rewrites is to exploit user-agent information in request. Apache/httpd allows to handle user-agent information and do a redirect of rewrite.
For approach a) you will redirect to your mobile site after identifying that user-agent is mobile user-agent and for approach b) you could rewrite the url (not redirect) add a selector that allows for you AMP specific resource scripts to render the content. Selector based solution is one possible way of implementing the single site for both web and AMP
UPDATE:
Assuming that you need to cache both AMP version and normal HTML markup, the solution is to use a special selector for rendering AMP version of markup. You could setup a component hierarchy -
Lets say your base page structure is abstracted out in a custom component called - AbstractPageComponent (this in most cases is replica of foundation/components/page customized to project need) and all your page components extend this component. What you could do is create another such component lets say AMPAbstractPageComponent, setup this page structure similar to standard Abstract component i.e. let it have its own copy of scripts head,body,content, header,footer etc. But make sure you name them differently from the convention in AbstractPageComponent, u could do that by pre-pending amp to them like amp-head.html, aem-body.html,amp-content.html. Then there will be AMPAbstractPageComponent.html the component rendering script that structures the page by including relevant AMP scripts and/or AbstractPageComponent scripts.
Each of these scripts should have the AMP specific logic and where-ever you need to refer to HTML logic include/defer to the AbstractPageComponent's script.
Now define the selector script to ensure AMP specific rendition, let say your selector is amp then in AbstractPageComponent create a amp.html or amp.jsp and in this script include AMPAbstractPageComponent.html
NOTE: The ideal structure to implement will be foundation Page -> AbstractPageComponent -> AMPAbstractPageComponent -> Other page templates
I have specified AMPAbstractPageComponent to be parent of AbstractPageComponent assuming that your site already exists and there is content pages referring to existing structure. If your site structure permits you to introduce AMPAbstractPageComponent between AbstractPageComponent -> Other page templates then you should do that and let AMPAbstractPageComponent handle that amp selector.
What i have defined above is the first level of change, next you need to consider the components inclusion that have AMP specific handling. For components included in templates you need pass on the selector amp if its coming in the URL otherwise included component will render their default script (component included in the templates not drag and dropped components).Dragged and dropped components will automatically try to render amp script if available and in case its not then default to its own script.
Please note, this is approach based on the selector resolution, for actual implementation to do AMP specific work you may have to do other stuff as well, another thing i have not included is the managing component rendering i.e if you normal html includes a parsys and that script in not included in your AMP implementation your components will not render. So you will either have to duplicate those inclusions in AMP specific scripts or you will have to include the AbstractComponent's scripts to include such components
Do a small PoC, I gave the approach solely based on high level understanding of what AMP does by reading the link you have specified.
I'm actually thinking about implementing the same and here is the thought path laid out so far (untested):
add new page extension handler at foundation/components/primary/cq/page (overlay it under /apps) named Page.amp.jsp with <%#include file="proxy.jsp" %> content
add page renderer into your application logic at the same place where are you rendering html pages
The rest should be done by ootb sling URL resolution handler
In Grails Asset Pipeline, I am serving HTML, js, CSS, and image files.
In an HTML asset, if I need to supply a src for an image, how should I write that URL to take into account:
that assets might be served from a different base URL, as specified by grails.assets.url
that assets might be served from the Grails server (in dev mode), but under a potentially variable app context
I can think of the following solutions:
always use relative paths between assets.
The problem with this is that if I ever move an asset, then all of its relative links must change.
Another possible issue would be that, if I somehow made Asset Pipeline route proprietary assets to my own static server, and thrid-party assets to public CDNs (e.g., https://ajax.googleapis.com/ajax/libs for angularjs, jquery, etc.), then any static relative URLs wouldn't work.
I assume that I shouldn't ever directly reference js and/or css files outside of Asset Pipeline manifests, so, unless that's wrong, then this problem shouldn't occur for those file types, but, if there's a CDN for common images (does such a thing exist?), then static relative URLs in html files wouldn't work in img src attributes.
angularjs & a javascript variable set via a gsp
Use angularjs in the html file to read a javascript variable that contains the base URL. Set the base URL in a gsp that is referenced by every page.
The problems with this are:
that a separate request for the gsp is necessary (though it should be able to be cached for a long time). Is it possible to compile a gsp at build-time into a js file, and copy the result as an asset, so that it could be included in the Asset Pipeline static bundle rather than served from my Grails server?
that browser cycles are used processing the angularjs code
that certain third-party javascript libraries don't play well with angularjs, so it might be complex to get them working with this setup
from what I know, url() calls in css would still have to be relative, since angularjs wouldn't be able to influence them. Maybe I could use one of the css wrapper languages, like less, but this option is getting much more complicated than option 1...
Are there any other viable options?
Are there any other cons and/or gotchas to either option that I've mentioned above?
I'm using the current version of Asset Pipeline (2.2.5), and the latest version of Grails 2.x (2.5.0).
I have a fully developed Angularjs frontend app (with the routes and everything set up) and would like to change the current backend to a Play 2 Java. What is the best approach to display the existing html files from Angular in Play? I have found a few examples of how to connect the routes, but I would rater not create an index.scala.html file as I would like to have the two frameworks separated as much as possible and having Play only working as backend.
If you don't want to dynamically generate views from Play using Twirl and you just want to serve your HTML static files publishing them as assets is the way to go. By default assets are designed to provide resource like CSS or JS files but nothing prevents you from serving ordinary HTML views as well.
Simply put your index.html in the public directory and modify the conf/routes files so it can handle all requests:
GET /*file controllers.Assets.at(path="/public", file)
This way your index.html will be accessible at www.yourdomain.com/index.html. Remember to put this line as the last mapping in the file as it matches all possible URLs. Other services should be declared above it.
From Yahoo!'s Best Practices for Speeding Up Your Web Site document:
Expires headers are most often used with images, but they should be
used on all components including scripts, stylesheets, and Flash
components.
I follow the above advice using the "mod_expires" Apache module. My implementation is much like HTML5 Boilerplate's. See this .htaccess code.
Here is another quote from the same Yahoo! document:
Keep in mind, if you use a far future Expires header you have to
change the component's filename whenever the component changes. At
Yahoo! we often make this step part of the build process: a version
number is embedded in the component's filename, for example,
yahoo_2.0.6.js.
I have taken care of this with my CSS and JavaScript files using Mark Story's Asset Compress plugin. It's just a matter of making Asset Compress' shell part of the build process.
Now for the two issues I've run into, both related to images:
I have regular <img> tags throughout my websites and I also have CSS background-images. I currently don't have an elegant way of handling cache busting for either of those two types of images. For <img> tags, I have this line in my "core.php" file:
Configure::write('Asset.timestamp', 'force');
Although this does provide a way of automatically handling cache busting for <img> tags (provided the tags are generated using $this->Html->image(...)), I don't consider this to be elegant for two reasons:
It uses a query string, which is not recommended.
The image's timestamp is checked every time that particular view is accessed. Yes, you could cache the view, but you may want the image(s) in that view to be updated before the cached version of the view expires, so you would have to do whatever is needed to trigger that view to be re-cached, which I don't consider to be elegant.
As for handling the cache busting of CSS background-images, I have to manually update the LESS file. Definitely not elegant.
How is image caching supposed to be handled with CakePHP and/or Asset Compress?
Cache Invalidation, performance and the web
It's commonly held that one of the hardest things to do in programming is cache invalidation. However with assets (js files, css files, images etc.) that's not really true optimal logic for serving web assets is:
Serve with long cache expiry (1 year)
Don't use etags
If the asset changes change the url
There is however one complication when applied to the web.
Consider a request for /css/main.css, containing:
body {
background-image:url('../img/bar.gif');
}
This will, obviously, trigger a request for /img/bar.gif when the css file is loaded. Assuming the image is served with appropriate headers, there are only two ways to load an updated version of bar.gif:
change the contents of the css file
change the folder where the css file is
The first is problematic if it's not automated (and even if automated, could go wrong) the second is easy.
Version-prefix asset urls -> never have problems again
One simple way to solve the css/js/files problem is to make your build number part of the url:
/v123/css/foo.css
^
You can do this by modifying your app helper webroot function for example:
public function webroot($file) {
$file = parent::webroot($file);
if (Configure::read('debug')) {
return $file;
}
return '/' . Configure::read('App.version') . $file;
}
Incidentally it's the same technique to use a cdn - probably the best thing you can do to improve frontend performance.
In this way when you bump your site version - all assets get new urls. Note that using this technique, all referenced assets need to use relative urls, not absolute:
.foo {
/* background-image:url('/img/bar.gif'); // won't work */
background-image:url('../img/bar.gif');
}
Otherwise the request for the css file is application-version specific but the referenced image is not and would be read from browser cache (if relevant) even with a new application version.
Achieving the same result, no changes to file system
You can use a rewrite rule similar to the one in h5bp's for filename cache-busting if you don't want to change your folder structure:
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/v\d+/(css|files|js)/(.+)$ /$1/$2 [L]
</IfModule>
This will mean that the url /v123/css/main.css serves the contents of /css/main.css at the time of the request.
Parsing css files is complex
You mention in a comment
I think the fact that changing one asset causes all assets to be re-downloaded is a deal-breaker
Unless you are releasing a new production version every minute - it's not going to be a problem (unless you have GB of cached content in which case .. you have different problems). The only way to have performant cache logic that is file specific is to e.g. store each file in your site as the sha1 of the file's contents - applied to css files that means replacing ../img/foo.gif with ../img/<hash of foo.gif's contents>.gif.
There's nothing to stop using multiple techniques, for example with the following structure:
app
webroot
css
img <- css assets only
fonts
img
js
You can version-prefix your css, fonts and js requests; indirectly do the same for css-images (assuming they use relative urls of the form background-image:url('img/bar.gif');) without applying the same logic to other assets (user avatars, their uploaded cat videos, whatever).
Or use data uris for all images
It's what google does =).
At the end of the day it becomes a choice between how complex you want your build process to be, and for what real benefit. Many users have empty browser caches, so it's quite likely that for a random user the cache logic of an application will only apply to their current visit - one of the main reasons why expiring your whole asset cache in one go isn't such a bad thing.