I am designing a very big application now and i want to make good infrastructure for the future.
In Razor (MVC) there is an option to include javascript files in a view by using the function #Scripts.Render("~/Scripts/myscript.js") by specify a specific file or bundle item from BundleCollection which defined in BundleConfig.cs.
I am wondering, is there any added value to define a bundle item in the Scripts.Render function of only single file instead of specify the script file itself?
one of added value i found is that in the long run i will be able to add more files to the bundle as needed without changing the views that using it and i will enjoy the optimization. but i couldn't find added value for that while i am still using one js file in the "bundle".
There is a couple of benefits actually apart from the one you have mentioned:
Bundles are minified in release mode. When you add a file to the bundle (even a single file) and reference the bundle in the view the code will be minified. It's not the case when you reference the file directly. That's most probably what you're going for in production.
The framework generates and appends a random hash to the script with every new version of the bundle to invalidate the cache of the previous bundles. It looks something like this <script src="/bundles/myscript.js?v=CQJxkNd9QnrvutTyUG9mM-vD0FrbCc1"></script>. Your clients will thank you for this after every new release. And again - it doesn't happen if you reference the file directly unless you generate and append the versions manually.
So what I usually do, and I consider it a good practice until I'm proven wrong, I create a bundle for every page specific needs even if it consists of a single js file with a tiny module. For example Home page:
bundles.Add(new ScriptBundle("~/bundles/home").Include("~/Scripts/home.js"));
#Scripts.Render("~/bundles/home")
Related
Recently I switched over from the legacy css integration to using the current method of css support via the CN1 Preferences dialog. Ever since then, I've had repeated problems accessing strings from the localization resource file.
A few important points:
I have two theme files, but even importing the strings as a csv file into the theme generated by css doesn't work
I've tried all possible combinations of theme initialization with the two theme files, including initializing just one of them, with no consistent success (occasionally it works, but then if I modify the css and the theme file gets regenerated it stops working again)
I created a brand new project and copied my code into it, imported the string files, and it worked - until I turned on css support. Then I was back to square one
When it fails to work, the method UIManager.getL10NResourceNames() returns an empty array
Any help would be greatly appreciated!
CSS controls the file and as a result you can no longer change the theme.res file by other means. You need to keep a separate localization.res file and load that strictly for the localization functionality of your application. You can use Resources.open("/localization.res") to load an arbitrary resource file.
After much poking around, I found the solution. It turns out my situation was the result of a few non-standard things I did. First of all, I had a theme.res file which I renamed using IntelliJ's Refactor >> Rename function, which renamed the hardcoded css theme name in the build.xml file to my new name. I needed to manually revert that string in order to prevent the css compile task from overwriting my theme file. The second thing I noticed is that sometimes (I'm not clear on what caused this) the theme file was not being refreshed in the /out directory when running the app locally. This would manifest itself, for instance, when I would add an image in the theme file, but when running the code it wouldn't be able to find it in the Resources hashtable. Every time this happens, I now know to just delete the contents of /out, thereby forcing the IDE to rebuild/recopy the theme file (I could probably just copy it manually to the /out directory, but I think deleting it is safest).
I'm ASP.NET MVC v4 for my application, and I'm using the web optimization features (bundling and minification of scripts and styles).
Now, what I understand is (please correct me if wrong), the optimization framework will look at the included files at the time of compilation and configure them. It'll create a version number (v=something) based on the contents. Every time the contents change, it'll recreate the version hash, and the client will get updated files.
Now, is there a way to get the following done
[1] Update something inside a js file in my server, and serve the updated one to the clients without re-building & re-starting the application (I'm not changing bundle configuration here, just updating file content inside a script) ?
[2] Update the script configuration itself (e.g. adding a new script to a bundle), and get that served to the clients without Re-compiling & Re-staring the application? Or, at least without re-compiling? (I know, generally we define the bundles inside cs files, but wondering if there is a way out!)
[3] Is there a way to use my own version number (say from a config file, v=myCustomScriptVersion) rather than the auto-generated version hash?
It's bit late, but I'm just sharing my experience on my own questions here.
As discussed in the comments of the question, bundles are defined as part of a cs file (generally BundleConfig.cs inside App_Start). So, the bundles are defined at compile time, and at application start they will get added to collection and become usable.
Now, the interesting bit. At run-time, the optimization framework looks into the included files and creates a hash of the contents, and appends that as a version query-string to the bundle request. So, when the bundle is called the generated uri is like the below one.
http://example.com/Bundles/MyBundledScripts?v=ILpm9GTTPShzteCf85dcR4x0msPpku-QRNlggE42QN81
This version number v=... is completely dynamic. If any file content within the bundle is changed, this version will be regenerated, and will remain same otherwise.
Now to answer the questions,
[1] This is done automatically by the framework, no need to do anything extra for this. Every time a file content is changed, new version number will be generated and the clients will get the updated scripts.
[2] Not possible. If files included in a bundle are changed, is has to be recompiled.
[3] Yes, it can be used. The custom version number can be added as below.
#Scripts.Render("~/Bundles/MyBundledScripts?v=" + ConfigurationManager.AppSettings["ScriptVersion"])
But Caution! This will remove the automatic versioning based on file contents.
And, additionally, if there are multiple versions of the same file available and we always want to include the latest version available, that can be achieved easily by including a {version} wildcard in bundle configuration like below.
bundles.Add(new ScriptBundle("~/Bundles/MyBundledScripts")
.Include(
"~/Scripts/Vendor/someScript-{version}.js"
));
So, if there are 2 scripts in the /Scripts/Vendor folder
someScript-2.3.js
someScript-3.4.js
Then the file someScript-3.4.js (higher version) will get included automatically. And when a new file someScript-4.0.js is added to the folder, that will be served to clients without any need for recompile/restart.
So I’m starting with mvc and I find hard to remember the name of my bundles. When using visual studio it seems easier to just drag and drop the script I need instead of going to my app_start folder and check the name of my bundle.
Am I doing something wrong? Is there any way to show my bundles when I write Styles.Render.
I’m using reshaper too but no option is showed.
Here is an example.
Seems easier to drag and drop my script/style:
Than writing #styles.render() because it won’t show my bundles so I have to go to my app_start folder and copy-paste it (What I actually do).
If there is an easier way please let me know.
Thanks
Normally you'd create a _layout.cs that imports the styles for most pages, that solves most of your issues, since you only have to do it once. Then what I normally do is create a bundle config for a specific page that has the same name as the controller or view (easy to remember) which has the page specific styles and scripts. The Bundle Config is where I set this up. Resharper (8.1) does help me when selecting paths from my bundle configuration.
Am looking to integrate SquishIt with our webapp. What I have noticed from the testing locally is, SquishIt generates the file only once. Based on other SO answers and reading the SquishIt code I gather that the file generation happens if the HttpCache doesn't contain a value of the generated hashed key.
If without restarting the app, or without clearing the HttpCache, if I delete the generated minified file, then SquishIt doesn't recreate the file.
Is there any way to force SquishIt to recreate the file, if it doesn't exist?
Earlier we were using RequestReduce and we noticed the it didn't always pick up css/js changes if only the css/js files were edited (ie, web.config was not edited and the app was not restarted). To ensure that the changes are picked up, we always delete all generated files when deploying.
Will SquishIt ALWAYS detect the changed code, even if web.config is not modified, the app is not restarted and the HttpCache is not cleared?
The [BundleCache.Add] (https://github.com/jetheredge/SquishIt/blob/master/SquishIt.Framework/BundleCache.cs#L40-54) method's code helps answer this question
Can I force SquishIt to generated files by simply deleting the generated files?
After thinking about the scenario I need to handle, this is the wrong question to ask.
EDIT:
What are the cache headers sent to the client for these generated files?
My scenario is as follows. I switched from the default JS minifier to JsMinMinifier. After deleting the files (RenderOnlyIfOutputFileIsMissing is set) and restarting the app, the minified files got generated. However, they had the same name as the previous files (I wrongly assumed it would have a different name).
Refreshing my browser showed that the newly generated files were sent by the server. How did this happen? If the assets had a long expiration cache header set on them, then the browser shouldn't have requested the new file from the server. (Inspecting the assets in Firebug, I am unable to understand the cache policy. To me it looks like it's set to cache for a couple of mins).
EDIT 2:
My take away is, there is no need to delete the generated file to cause regeneration. If the corresponding source files change, SquishIt WILL generate an appropriate file.
It should - we are adding cache dependencies for source files (not the generated ones) so if one of them is edited the entry in the bundle cache should be invalidated. See BundleCache.Add
No - once an entry is in the bundle cache we assume the output file will be there, so you'd end up with the file not being found. This is by design, we haven't really heard a compelling case against it.
Deleting generated files when deploying should be fine though, even if not strictly necessary - don't you need to restart the app then anyway?
If you are really concerned about files lingering you may want to consider using SquishIt without the file system
Simple question, could'nt find a straight answer. How can I modify the output file name of a T4 Template?
I'm using a T4 Template to bundle and minify all my javascript files. Now I want to include the current Assembly Hashcodein my filename. But how can I access this filename?
A workaround would be to rename the ouput file after generating it but this doesnt't seem nice to me.
You need to do something called auto-versioning, and this is usually done by URL rewriting. The physical files are not actually renamed.
See this question for details on javascript and css auto versioning:
How to force browser to reload cached CSS/JS files?
Note that if you use templates to generate a different physical file for every time you generate a file then you will lose a lot of benefits of source control (revisions etc), and you will end up with an unmanageably large set of files on disk.