Content versioning for angularjs with Asp.net - asp.net

Does anybody know the best approach for versioning static content such as .html, .js, .cc, etc. when using ASP.NET and angularjs.
So far the only thing I found is manipulating Etag in custom httpmodule.
Any ideas?

Take a look at Bundling and Minification in ASP.Net
http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification
This will add versioning to your .jS and .CSS assets. It is a good starting point and can be extended with plugins or custom configuration/code to fit your needs.
There are plugins that support TypeScript, CoffeeScript, Less and Sass.
The other benefit to this is that as well as versioning your assets, this will bundle them together to reduce requests -- and minify them to reduce size.

You can use Grunt to build your js, css etc. All you need to do asset versioning is use grunt-filerev and grunt-usemin plugins.
The first one will version files in the file system and the second one will update all static references throughout html and css to the versioned files.
I have done the same in a web.api / angularjs project using something as simple as:
filerev: {
options: {
encoding: 'utf8',
algorithm: 'md5',
length: 8
},
all: {
src: [
'<%= project.dist %>/scripts/spa.min.js',
'<%= project.dist %>/images/**/*.{jpg,jpeg,gif,png,svg,ico}',
'<%= project.dist %>/styles/spa.min.css'
]
},
},
usemin: {
html: 'index.html',
css: 'Content/**/*.css'
},
Note: the above does revisioning. If you need to add a version number you can take a look at grunt-version (I am doing revisioning with a banner on top of generated files with version and timestamp instead)

Related

with webpack, why should one import CSS files from JS source code and not build CSS in isolation like the tradition did?

webpack doc for loading css:
https://webpack.js.org/guides/asset-management/#loading-css1
The webpack doc asks to import the CSS files from the Javascript code and to then run extract-text-webpack-plugin to extract the CSS.
--> with webpack, why should one import CSS files from JS source code and not build CSS in isolation like the tradition did?
By not importing CSS from Javascript, I mean that the webpack config for CSS has no ".js" extension, and it parses the CSS/SCSS files directly.
There are benefits of not importing CSS from javascript:
(objective fact). If one wants to build only CSS, it will be faster if the bundler does not need to parse the Javascript source code. Besides, one can run the bundlers for CSS and Javscript in parallel by using parallel-webpack.
(subjective, based on tradition, but most important in my opinion). SASS building in isolation has been the tradition for years. Therefore, we can achieve better HTML semantics and maintainability. Importing CSS from JS is virtual and may lead to neglect the generated separate CSS bundle.
(objective fact) One can split more the config files for CSS and Javascript, for more clarity.
I'm more a traditionalist than most as i've been doing this for over 15 years, but I would say the new way to separate concerns is better than the traditional way.
In the old thinking we use to separate layout from styling from functionality (html from css from js). This is more 'vertical' and made knowing where files are easy, but made finding specific code to do with 'features' hard. I.e. a button might be made up of a small button section within /src/shop-front.html, a few lines of code within /src/css/shop-front.css and then the enhanced functionality would live somewhere in /src/js/shop-front.js
The new way of thinking is to separate concerns by components. So now you would have your shop-front, but this would be made from /src/components/button/ and all files will live in the same place. Including the js file which includes the css as mentioned.
The benefit being, if you decide to swap button for fancy-button all you do is change the shop-front import button from 'button' to import button from 'fancy-button'. all old code will be removed automatically. no need to try to digest and change code in multiple places.
To address your concerns:
true, node-sass is fast, but I would say the difference between that and going via webpack is negligible and the improvement in dev experience (as mentioned above) is worth any extra ms
This point does apply as the way the css/sass is built does not change just because we require it from a js file. I guess you mean if you were to use css modules, but this is a choice, you don't have to. I use sass and apply class names as i would normally.
In webpack config, you could split the js config from the css config if you wanted to. I wouldn't argue that this would make things any clearer though. the config is so small, it's not worth worrying about.
My folder structure is nice and easy to reason with:
This is a basic config for simple scss imports
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { SRC, DIST } = require('./src/config/paths');
module.exports = {
devtool: 'source-map',
cache: true,
context: SRC,
entry: {
app: [`${SRC}/client-entry.js`]
},
output: {
path: DIST,
filename: '[name]-[chunkhash].js',
publicPath: '/'
},
plugins: [
new ExtractTextPlugin('[name]-[contenthash].css'),
],
resolve: {
modules: ['node_modules', SRC],
extensions: ['.js', '.jsx', '.scss']
},
module: {
rules: [
{
test: /\.jsx?$/,
include: [/src/],
loader: 'babel-loader',
options: {
cacheDirectory: true
}
},
{
test: /\.s?css$/,
include: [/src/],
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', 'sass-loader']
})
}
]
}
};

Webpack "OTS parsing error" loading fonts

My webpack config specifies that fonts should be loaded using url-loader, and when I try to view the page using Chrome I get the following error:
OTS parsing error: invalid version tag
Failed to decode downloaded font: [My local URL]
The relevant parts of my config look like this:
{
module: {
loaders: [
// ...
{
test: /\.scss$/,
loaders: ['style', 'css?sourceMap', 'autoprefixer', 'sass?sourceMap'],
},
{
test: /images\/.*\.(png|jpg|svg|gif)$/,
loader: 'url-loader?limit=10000&name="[name]-[hash].[ext]"',
},
{
test: /fonts\/.*\.(woff|woff2|eot|ttf|svg)$/,
loader: 'file-loader?name="[name]-[hash].[ext]"',
}
],
},
}
It doesn't happen in Safari, and I haven't tried Firefox.
In development I'm serving files through webpack-dev-server, in production they're written to disk and copied to S3; in both cases I get the same behaviour in Chrome.
This also happens to larger images (greater than the 10kB limit in the image loader config).
TL;DR Use absolute paths to your assets (including your complete hostname) by setting your output.publicPath to e.g. "http://example.com/assets/".
The problem
The problem is the way that URLs are resolved by Chrome when they're parsed from a dynamically loaded CSS blob.
When you load the page, the browser loads your Webpack bundle entry JavaScript file, which (when you're using the style-loader) also contains a Base64 encoded copy of your CSS, which gets loaded into the page.
This is what it looks like in Chrome DevTools
That's fine for all the images or fonts which are encoded into the CSS as data URIs (i.e. the content of the file is embedded in the CSS), but for assets referenced by URL, the browser has to find and fetch the file.
Now by default the file-loader (which url-loader delegates to for large files) will use relative URLs to reference assets - and that's the problem!
These are the URLs generated by file-loader by default - relative URLs
When you use relative URLs, Chrome will resolve them relative to the containing CSS file. Ordinarily that's fine, but in this case the containing file is at blob://... and any relative URLs are referenced the same way. The end result is that Chrome attempts to load them from the parent HTML file, and ends up trying to parse the HTML file as the content of the font, which obviously won't work.
The Solution
Force the file-loader to use absolute paths including the protocol ("http" or "https").
Change your webpack config to include something equivalent to:
{
output: {
publicPath: "http://localhost:8080/", // Development Server
// publicPath: "http://example.com/", // Production Server
}
}
Now the URLs that it generates will look like this:
Absolute URLs!
These URLs will be correctly parsed by Chrome and every other browser.
Using extract-text-webpack-plugin
It's worth noting that if you're extracting your CSS to a separate file, you won't have this problem because your CSS will be in a proper file and URLs will be correctly resolved.
For me the problem was my regex expression. The below did the trick to get bootstrap working:
{
test: /\.(woff|ttf|eot|svg)(\?v=[a-z0-9]\.[a-z0-9]\.[a-z0-9])?$/,
loader: 'url-loader?limit=100000'
},
As asnwered here by #mcortesi if you remove the sourceMaps from the css loader query the css will be built without use of blob and the data urls will be parsed fine
As with #user3006381 above, my issue was not just relative URLs but that webpack was placing the files as if they were javascript files. Their contents were all basically:
module.exports = __webpack_public_path__ + "7410dd7fd1616d9a61625679285ff5d4.eot";
in the fonts directory instead of the real fonts and the font files were in the output folder under hash codes. To fix this, I had to change the test on my url-loader (in my case my image processor) to not load the fonts folder. I still had to set output.publicPath in webpack.config.js as #will-madden notes in his excellent answer.
I experienced the same problem, but for different reasons.
After Will Madden's solution didn't help, I tried every alternative fix I could find via the Intertubes - also to no avail. Exploring further, I just happened to open up one of the font files at issue. The original content of the file had somehow been overwritten by Webpack to include some kind of configuration info, likely from previous tinkering with the file-loader. I replaced the corrupted files with the originals, and voilĂ , the errors disappeared (for both Chrome and Firefox).
I know this doesn't answer OPs exact question but I came here with the same symptom but a different cause:
I had the .scss files of Slick Slider included like this:
#import "../../../node_modules/slick-carousel/slick/slick.scss";
On closer inspection it turned out that the it was trying to load the font from an invalid location (<host>/assets/css/fonts/slick.woff), the way it was referenced from the stylesheet.
I ended up simply copying the /font/ to my assets/css/ and the issue was resolved for me.
Since you use url-loader:
The url-loader works like the file-loader, but can return a DataURL if the file is smaller than a byte limit.
So another solution to this problem would be making the limit higher enough that the font files are included as DataURL, for example to 100000 which are more or less 100Kb:
{
module: {
loaders: [
// ...
{
test: /\.scss$/,
loaders: ['style', 'css?sourceMap', 'autoprefixer', 'sass?sourceMap'],
},
{
test: /images\/.*\.(png|jpg|svg|gif)$/,
loader: 'url-loader?limit=10000&name="[name]-[hash].[ext]"',
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=application/font-woff',
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=application/font-woff',
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=application/octet-stream',
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader',
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=100000&mimetype=image/svg+xml',
},
],
},
}
Allways taking into account on what the limit number represents:
Byte limit to inline files as Data URL
This way you don't need to specify the whole URL of the assets. Which can be difficult when you want Webpack to not only respond from localhost.
Just one last consideration, this configuration is NOT RECOMMENDED for production. This is just for development easiness.
The best and easiest method is to base64 encode the font file. And use it in font-face.
For encoding, go to the folder having the font-file and use the command in terminal:
base64 Roboto.ttf > basecodedtext.txt
You will get an output file named basecodedtext.txt. Open that file. Remove any white spaces in that.
Copy that code and add the following line to the CSS file:
#font-face {
font-family: "font-name";
src: url(data:application/x-font-woff;charset=utf-8;base64,<<paste your code here>>) format('woff');
}
Then you can use the font-family: "font-name" in your CSS.
I just had the same issue with Font Awesome. Turned out this was
caused by a problem with FTP. The file was uploaded as text (ASCII)
instead of binary, which corrupted the file. I simply changed my FTP
software to binary, re-uploaded the font files, and then it all
worked.
https://css-tricks.com/forums/topic/custom-fonts-returns-failed-to-decode-downloaded-font/
this helped me in the end
I had the same issue with FTP transferring files as text
If you're using Angular you need to check to make sure your
<base href="/">
tag comes before your style sheet bundle. I switched my code from this:
<script src="~/bundles/style.bundle.js"></script>
<base href="~/" />
to this:
<base href="~/" />
<script src="~/bundles/style.bundle.js"></script>
and the problem was fixed.
Thanks to this post for opening my eyes.
As of 2018,
use MiniCssExtractPlugin
for Webpack(> 4.0) will solve this problem.
https://github.com/webpack-contrib/mini-css-extract-plugin
Using extract-text-webpack-plugin in the accepted answer is NOT recommended for Webpack 4.0+.
The limit was the clue for my code, but I had to specify it like this:
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
},
},
],
In my case adding following lines to lambda.js {my deployed is on AWS Lambda} fixed the issue.
'font/opentype',
'font/sfnt',
'font/ttf',
'font/woff',
'font/woff2'
Had same problem like #adam-mccormick and user3006381. I am using webpack5 and hot module.
My .eot or .woff files contained:
export default __webpack_public_path__ + "./fonts/montserrat-v24-latin-ext-regular.woff2";
and my webpack.config.js looked like:
modules.exports = {
//...
module: {
rules: [
//...
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
use: [{
loader: "file-loader",
options: {
name: './fonts/[name].[ext]',
}
}]
}
]
}
}
and this was my problem solution:
modules.exports = {
//...
module: {
rules: [
//...
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: './fonts/[name].[ext]',
}
}
]
}
}

How to include semantic-ui fonts using bower and ember-cli

I want to use semantic-ui within ember-cli project, having trouble with including fonts.
bower install semantic-ui
Import css and fonts in Brocfile.js
app.import('bower_components/semantic-ui/dist/semantic.css');
app.import('bower_components/semantic-ui/dist/semantic.js');
var semanticFonts =
pickFiles('bower_components/semantic-ui/dist/themes/default/assets/fonts', {
srcDir: '/',
files: ['**/*'],
destDir: 'assets/themes/default/assets/fonts'
});
This works, because semantic.css looks for themes/default/assets/fonts relative to itself.
Note the destDir: 'assets/themes/default/assets/fonts', this is because ember-cli puts the semantic-css within assets/ folder, and I have to put the fonts in that folder. But this looks like a hack is there a better solution?
Finally semantic-ui dist folder doesn't include different build options, do I have to compile the project myself eg: using gulp?, I thought using bower it should be straightforward.
We also got 404's for the fonts after installing Semantic via Bower. We solved it by adding the font folder as a tree to the Ember build.var
EmberApp = require('ember-cli/lib/broccoli/ember-app');
var pickFiles = require('broccoli-static-compiler');
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
babel: {
includePolyfill: true
},
fingerprint: {
extensions: ['js', 'css', /*'png', 'jpg', 'gif',*/ 'map']
}
});
app.import('bower_components/semantic/dist/semantic.css');
app.import('vendor/shims.js');
var semanticIcons = pickFiles('bower_components/semantic/dist/themes/default/assets/fonts', {
srcDir: '/',
destDir: '/assets/themes/default/assets/fonts'
});
return app.toTree([semanticIcons]);
};
Looking at semantic-ui, it seems pretty gigantic, and specifically setup with gulp.
First off, I would use the flag --save in your bower request.
bower install --save semantic-ui
This will add it as a dependency to your bower.json automatically - or --save-dev if it's only for development and not production.
Semantic-ui looks like it's written in "LESS", so not only do you have to deal with a favored build tool, but also it has opinions about the preprocessor.
The fonts involved seem to be just some google includes, and some svg fonts.
My advice, if you really really want to use a monstrous set of CSS declarations like this, - in this situation - would be to take the /dist output .css and .js -and- combine it with YOUR favorite css pre processing setup - and just override where appropriate. - or borrow the forms or whatever specific styles lead you to want to use this.
I am worried that fully integrating it into your ember project wont be as smooth as intended... and that you won't get a terribly useful amount of stuff out of keeping it in sync.
Just my opinion, - but I can't comment yet. - and I think you would be better off just writing the styles in stylus from scratch anyways. : )
I had the same problem.
I don't know if there's a better way, but I added the following line to the config/application.rb
config.assets.paths << Rails.root.join('vendor', 'assets', 'bower_components', 'semantic-ui', 'dist')
This adds the dist folder to the asset path, so when semantic-ui is looking for /themes, it will be picked up.

How to make grunt not minify certain js files

My grunt script generated by yeoman concats and minifies js files through useminPrepare, concat, and uglifyjs.
This is working great, but there is one js script that I do not want it to minify. How do I specify that in the grunt file?
What you can do it's to put the files you don't want to minify outside of the build script, for example:
<!-- build:js js/app.js -->
<script src="js/app.js"></script>
<script src="js/minifythis.js"></script>
<script src="js/models/minifythis.js"></script>
<!-- endbuild -->
<script src="js/do-not-minify-this.js"></script>
I spent days looking for a solution to a problem similar to yours, and then I found a different question that has a answer that may fit solve your problem, as it solved mine: https://stackoverflow.com/a/24819171/785985
The solution is to define custom blocks to be processed by Grunt. Then you can specify one block with ['concat'] and another with ['concat', 'uglifyjs'].
If you choose to exclude the files from the minification tag per the item from John Locke, don't forget to manually copy those files to the 'dist' dir. Normally, when you minify files the resultant minified library is copied to the dist dir. But since you're not minifying them, you have to copy them yourself.
For example, I didn't want to compress the user scripts in my app to make it easier for people to examine the code online. After editing my 'index.html' to remove them from the tag:
'<!-- build:js({.tmp,app}) scripts/scripts.js -->'
I had to add the following to the copy step of my Gruntfile:
copy: {
dist: {
files: [
...
{ // manually copy all the files you are not minimizing:
expand: true,
cwd: '<%= yeoman.app %>/scripts/',
src:"{,*/}*.js",
dest:"<%= yeoman.dist %>/scripts/"
}
]
},
...
},
The syntax for copying files is very prickly in Grunt. It took me a couple of tries to get it right.
Just need to set a minimize option of that script to false in Gruntfile.js.
optimization: {
minimize: false
}

Using r.js to concatenate CSS

I'm working on a project using require.js and plan to optimize it using r.js. The optimization for javascript files is built in as part of the require configration automatically.
What I would like is to split the CSS into several different files, e.g. head.css, body.css, main.css, etc. When r.js runs, it should concatenate these into a single file. The HTML would have:
<link rel=stylesheet type=text/css href=css/main.css>
A problem is that during development, the files will still be split up. I'd like to keep them split and don't want to have to redo the optimization every time -- even if it can be done automatically.
I'd also like to be able to keep the HTML with just the one stylesheet reference even in development. What would be the optimal way to do this?
There are several possibilities that I can see, each with potential problems:
Have main.css use #import to include all other CSS files.
Not automatic -- have to edit main.css for each file. That's not a big deal since the number of files will be relatively small and probably all known very early on.
r.js does not optimize this
Use require-css
This seems to be geared more towards AMD loading of CSS -- I'd rather load all the CSS up front
Same issues with automatic loading of CSS files as the other option
Create my own script that calls r.js without CSS optimization, concatenate all of the CSS files and minify appropriately.
I'm sure there's someone out there who has done this better than I will
I use grunt-contrib-cssmin which works great. You can also pass arguments to grunt, so you can have grunt:dist combine all your css and plain grunt will leave them separate.
module.exports = function (grunt) {
grunt.initConfig({
cssmin: {
add_banner: {
options: {
banner: '/* My minified css file */'
},
files: {
'dist/css/dist.min.css': ["bower_components/bootstrap/dist/css/bootstrap.css", "tmp/css/dist.css"]
}
}
}
})
}
Grunt getting started.
There is also a requirejs script for grunt. The setup looks like this:
requirejs: {
compile: {
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js",
out: "path/to/optimized.js"
}
}
}

Resources