So I currently use BundleTransformer, LESS and I'm trying to add the Autoprefixer post processor. This plugin automatically takes css like transform: scale(1.5) and converts it to -webkit-transform and -moz-transform.
If I am in release mode or have BundleTable.EnableOptimizations=true then everything works just fine and the prefixes are added as expected.
In debug mode however, all the individual CSS / LESS files in my bundle are present in the HTML as separate requests. I'm using this command in my CSHTML file:
#Styles.Render("~/Content/css/lessbundle")
i.e. In debug mode this gets expanded out to LINK tags for :
/cs/something.css
/css/lessfile1.less
/css/lessfile1.less
instead of a single file
/Content/css/lessbundle?v=RFAUSIwb-jEuuo4vHNTnTkE2LrN2jfHglX-Hk8HIF481
For the LESS files IIS automatically converts them, however it does not apply the Autoprefixer.
Is there a way to get Autoprefixer to work when requesting raw .css and .less files?
If not it seems kind of pointless to me because the only alternative I see is to request directly the 'Content/css/lessbundle virtual URL - which will get run through the Autoprefixer. It will only get minified for a release build.
In the documentation (sections: “Examples of usage”, “Debugging HTTP-handlers” and “Postprocessors”) describes how to solve this problem. I will list the basic steps:
For debugging HTTP-handlers to use a configuration settings from bundles need to add in the RegisterBundles method of App_Start/BundleConfig.cs file the following code:
BundleResolver.Current = new CustomBundleResolver();
In order to these settings can be applied to CSS- and JS-assets need to register the debugging HTTP-handlers CssAssetHandler and JsAssetHandler in Web.config file. To do this in the IIS Integrated mode, you need add to the /configuration/system.webServer/handlers element the following code:
<add name="CssAssetHandler"
path="*.css" verb="GET"
type="BundleTransformer.Core.HttpHandlers.CssAssetHandler, BundleTransformer.Core"
resourceType="File" preCondition="" />
<add name="JsAssetHandler"
path="*.js" verb="GET"
type="BundleTransformer.Core.HttpHandlers.JsAssetHandler, BundleTransformer.Core"
resourceType="File" preCondition="" />
To make AutoprefixCssPostProcessor is one of the default CSS-postprocessors, you need to make changes to the Web.config file. In the defaultPostProcessors attribute of \configuration\bundleTransformer\core\css element must be add AutoprefixCssPostProcessor to end of comma-separated list (for example, defaultPostProcessors="UrlRewritingCssPostProcessor,AutoprefixCssPostProcessor").
In addition to what #Taritsyn said you need to make sure your bundles are
CustomScriptBundle() and not ScriptBundle()
If not you will get the slightly confusing error message:
Could not find the transformer in the '~/Content/css/myCssBundle' bundle.
I found it interesting to look deeper into how this actually works
The HTML is written (just view source) with an additional parameter ?bundleVirtualPath
/Content/css/defenderrazor_DEBUG.less?
bundleVirtualPath=~%2fContent%2fcss%2fmyCssBundle
This is intercepted by the handler in the web.config when a .less file is requested and the handler is then able to use that bundle name to look up any transformations that you've set - including in this case the default post processor for AutoprefixCss.
Related
I have set up a simple test using ASP.NET's bundling and minification feature. I have two very simple js files:
~/JS/Site.js
(function echo1() {
alert("this is site.js");
})();
~/JS/test.js
(function echo2(value) {
alert("and this is test.js");
})();
I've created a bundle as follows:
bundles.Add(new ScriptBundle("~/bundles/scripts/site-globals").Include(
"~/JS/Site.js",
"~/JS/test.js"));
and referenced the bundle on the page using #Scripts.Render("~/bundles/scripts/site-globals")
When I run the site under debug (<compilation debug="true" targetFramework="4.5" /> in web.config) I get the expected result - two alert boxes show one after the other.
However, when I run change to release (<compilation debug="false" targetFramework="4.5" />) - I only see the first alert box, and the combined JS file that gets sent to the browser has completely ignored the content of test.js.
The "combined and minified" output is as below, and wrongly only includes the code from Site.js:
(function(){alert("this is site.js")})()
Any ideas on why this is happening would be much appreciated! Thanks
I've found out what was causing this problem. If any of the javascript files have a comment as the last line, they will be combined together without a newline, causing the first line of the next file to be commented out.
Here's a link to another question on stack overflow which demonstrates this: https://stackoverflow.com/a/14223945/11459631
In my case, I was using the Web Essentials Visual Studio plugin to minify my javascript files. It was creating a .js.map file for each JS file, and at the end of each .min.js file was a commented line like this, which turned out to be causing the problem:
//# sourceMappingURL=somefile.min.js.map
Since I didn't need the mapping files, I turned this feature off using Options -> Web Essentials -> Javascript -> Set Generate source maps (.map) to false
Hope this helps anyone who finds this problem!
Matt, your bundling code looks correct, do you receive any js errors in the browser console when running in Release mode? Also as a side note, are you aware that you can simply define the folder path to your JS files and they will all be included?
I want to add a simple stylesheet to a plone 4 product. Therfore I added
<browser:resourceDirectory
name="groovecubes.portlet.gallery.css"
directory="css"
/>
to [product dir]/browser/configure.zcml, which should me enable to browse stylesheets in this folder with this syntax: ++resource++groovecubes.portlet.gallery.css/mycss.css. But it doesn't. Not even after a buildout.
Every declaration in [product dir]/profiles/default/cssregistry.xml are therefore not found. What am I missing? Is it the package name?
The packages main configure.zcml contains the line
<include package=".browser" />
which should execute browser/configure.zcml
But is does not. I pasted the packages configure.zcml and browser/configure.zcml
Update II:
It gets even weirder. When I modifiy the head of browser/configure.zcml the file is recognized as malformed when I try to start the instance. But when I modify the relevant entry, startup continues normal.
Update III:
I've tested various things now, but what I found out, is that any malformed tags in .zcml files is ignored by the SaxParser. In every product on my dev and productive instance (Plone 4.2 / Plone 4.1). Is that maybe a new feature, I may have missed?
Update IV:
Solved: I removed the interface declaration from browser/configure.zcml that accidently used the same name. That made my .css available. But I'm still wondering about the described parser behaviour.
You declare the name groovecubes.portlet.gallery.css but try to access it as ++resource++groovecubes.portlet.gallery instead (note the missing .css there).
Either use ++resource++groovecubes.portlet.gallery.css/mycss.css or remove the .css part from the resourceDirectory registration.
If that was just a typo, check that the ZCML file is actually being loaded; the registration itself is fine if the names match.
I have set up an HttpHandler for *css to do some simple parsing:
<handlers>
<add name="CssHandler" verb="*" path="*.css"
type="MyApp.CssProcessor,MyApp.Assembly"/>
</handlers>
All was well until I added a resource that loads a css file dynamically, e.g.
<link rel="stylesheet" type="text/css" href="/loader.ashx/module.resource.css" >
To my surprise, things went horribly wrong. The custom http handler intercepts this, but since it's designed to just load files from the file system, it doesn't work. I realize that, technically, it matches a pattern *.css but that seems an odd behaviour, since the actual resource being requested from the web server is *.ashx and the css is only after the file path, as a parameter.
Is it possible to make the filter for a handler only apply to the actual server resource name?
Alternatively (and actually I'd like to know how to do this anyway) -- what I would really rather be doing is intercepting the output from the default css handler. That is, rather than having all my own code to actually load files from the file system in my CSS handler, it seems it would be far simpler to just take the response from the default handler and filter it. Which would have worked properly in this situation.
Finally, in either case, I'd much rather be filtering on resource MIME type text/css rather than intercepting requests by name, since what I really want to do is filter any CSS (rather than anything that happens to be named "*.css"). Any pointers on how to do this?
You could...
1) Modify your handler to check if a file exists.
2) Use an HttpModule to intercept the response. Not sure exactly what you're doing in this scenario, but actually modifying the output can get tricky.
3) Modify the argument being passed to loader.ashx to not end with .css (that's kind of hacky)
4) Try using a "?" as the separator between loader.ashx and the argument, since there are other requests (.axd) that often use querystring parameters and still work properly.
I'm trying to create theme for Orchard CMS. The template I have wasn't made for it so I have some troubles displaying images from Layout.cshtml.
This is the current folder structure on my web server (theme folder structure only):
Theme/Content/Images/Image.jpg
Theme/Views/Layout.cshtml
Theme/Styles/Site.css
The following line doesn't display image (located in Layout.cshtml):
<img src="../Content/Images/bgBig.jpg" alt="Big background image" />
However, this line does display the image (located in Site.css):
background-image:url('../Content/Images/bgLines.png');
I believe the problem is that Layout.cshtml doesn't display the image from Theme/Views/Layout.cshtml, but from the other location. If someone knows what would be that location or how to override it I would be thankful.
I might be a little late, but this may be of help to others.
To get the current theme and then build an dynamic path (as opposed to an absolute path) use this:
WorkContext.CurrentTheme: Gets the current working theme ExtensionDescriptor.
Then give it to the Html.ThemePath URL builder:
Ex.
Html.ThemePath(WorkContext.CurrentTheme, "/Content/Images/SomeImage.png")
Have fun!
Best regards,
Tiago.
When adding images in Layout.cshtml you should use the full path to your theme (eg. /Themes/My.Theme/Content/Images/MyImage.jpg). Remember that the paths you provide in [img] tag are relative to the URL in browser, not the path on the server. In MVC those are almost never equal.
Layout.cshtml view file gets loaded as a part of every single request, so relative paths placed inside will almost always break.
Imagine you have two Orchard pages: site.com/mypage and site.com/something/mypage. Layout.cshtml gets rendered in both of them. Relative URLs working for the first will surely break when you access second one.
CSS stylesheets are loaded directly by specifying absolute path to the physical files in /Themes/YourTheme/Styles folder (default), so in this case relative URLs will work.
HTH
Thx Tiago for your solution. I think this is in fact the correct solution, as opposed to linking the full path which I think would require the Orchard site to be on the root of the domain.
The full image reference of the original question would look like this:
<img src="#Url.Content(Html.ThemePath(WorkContext.CurrentTheme, "/Content/Images/bgBig.jpg"))" alt="Big background image" />
I'm surprised that nobody's mentioned that you need the following web.config in the folder in which your images/scripts/styles reside (see the orchard docs)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<httpHandlers>
<!-- iis6 - for any request in this location,
return via managed static file handler -->
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers accessPolicy="Script,Read">
<!-- iis7 - for any request to a file exists on disk,
return it via native http module.
accessPolicy 'Script' is to allow for a managed 404 page. -->
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule"
preCondition="integratedMode" resourceType="File"
requireAccess="Read" />
</handlers>
</system.webServer>
</configuration>
Additionally, as others have pointed out, this is the most reliable way of locating an image:
<img src="#Url.Content(Html.ThemePath(WorkContext.CurrentTheme, "/Content/Header.png"))" />
if you examine the source, it should show you where it's trying to find that image and failing. It's most likely the relative path it's having issue with, try an absolute path in the css to see if that's the issue. without the actual site, I can't know for sure.
Assume I have an "images" folder directory under the root of my application. How can I, from within a .css file, reference an image in this directory using an ASP.NET app relative path.
Example:
When in development, the path of ~/Images/Test.gif might resolve to /MyApp/Images/Test.gif while, in production, it might resolve to /Images/Test.gif (depending on the virtual directory for the application). I, obviously, want to avoid having to modify the .css file between environments.
I know you can use Page.ResolveClientUrl to inject a url into a control's Style collection dynamically at render time. I would like to avoid doing this.
Unfortunately Firefox has a stupid bug here... the paths are relative to the path of the page, instead of being relative to the position of the CSS file. Which means if you have pages in different positions in the tree (like having Default.aspx in the root and Information.aspx in the View folder) there's no way to have working relative paths. (IE will correctly solve the paths relative to the location of the CSS file.)
The only thing I could find is this comment on http://www.west-wind.com/weblog/posts/269.aspx but, to be honest, I haven't managed to make it work yet. If I do I'll edit this comment:
re: Making sense of ASP.Net Paths by
Russ Brooks February 25, 2006 # 8:43
am
No one fully answered Brant's question
about the image paths inside the CSS
file itself. I've got the answer. The
question was, "How do we use
application-relative image paths
INSIDE the CSS file?" I have long been
frustrated by this very problem too,
so I just spent the last 3 hours
working out a solution.
The solution is to run your CSS files
through the ASPX page handler, then
use a small bit of server-side code in
each of the paths to output the root
application path. Ready?
Add to web.config:
<compilation debug="true">
<!-- Run CSS files through the ASPX handler so we can write code in them. -->
<buildProviders>
<add extension=".css" type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
</compilation>
<httpHandlers>
<add path="*.css" verb="GET" type="System.Web.UI.PageHandlerFactory" validate="true" />
</httpHandlers>
Inside your CSS, use the Request.ApplicationPath property
wherever a path exists, like this:
#content {
background: url(<%= Request.ApplicationPath
%>/images/bg_content.gif) repeat-y;
}
.NET serves up ASPX pages with a MIME type of "text/html" by default,
consequently, your new server-side CSS
pages are served up with this MIME
type which causes non-IE browsers to
not read the CSS file correctly. We
need to override this to be
"text/css". Simply add this line as
the first line of your CSS file:
<%# ContentType="text/css" %>
In case you didn't know you could do this...
If you give a relative path to a resource in a CSS it's relative to the CSS file, not file including the CSS.
background-image: url(../images/test.gif);
So this might work for you.
Make you life easy, just put images used in your CSS in the /css/ folder alongside /css/style.css. Then when you reference your images, use relative paths (e.g. url(images/image.jpg)).
I still keep images that are displayed with a <img> in an /images/ folder. Photos for example are content, they are not part of the website's skin/theme. Thus, they do not belong in the /css/ folder.
Marcel Popescu's solution is using Request.ApplicationPath in the css file.
Never use Request.ApplicationPath - it is evil! Returns different results depending on the path!
Use the following instead.
background-image: url(<%= Page.ResolveUrl("~/images/bg_content.gif") %>);
Put your dynamic CSS in a user control in an .ascx file and then you do not need to run all your css files through the asp.net page processer.
<%# Control %>
<style type="text/css>
div.content
{
background-image:(url(<%= Page.ResolveUrl("~/images/image.png") %>);
}
</style>
But the easiest way to solve the ~ problem is to not use a ~ at all. In Visual Studio, in Solution Explorer, right click your application, select Properties Window and change the Virtual Path to /.
On Windows 7, IIS 7.5:
Not only do you have to do the steps mentionned by Marcel Popescu.
You also need to add a handler mapping in IIS 7.5 handler mappings. So that IIS knows that *.css must be used with the System.Web.UI.PageHandlerFactory
It's not enough to just set the stuff in the web.config file.
Inside of the .css file you can use relative paths; so in your example, say you put your css file in ~/Styles/mystyles.css. You can use url(../Images/Test.gif) as an example.
I was having difficulty in getting background images to display for content containers and have tried many solutions similar to other posted here. I had set the relative path in the CSS file, set it as a style on the aspx page I wanted the background to display - nothing worked. I tried Marcel Popescu's solution and it still didn't work.
I did end up getting it to work following a combination of Marcel's solution and trial and error. I inserted the code into the web.config, inserted the text/css line into my CSS file but I removed the background property in the CSS file altogether and set it as a style on the content container in the aspx page I wanted the background to display.
It does mean that for each or any other pages that I want to display the background I will need to set the style background property but it works beautifully.