How to block css cache without adding random number to it? - javascript

I have an angular project,which when uploaded to the server the css files are getting cached and the previous version files are served.So,then I started adding something like
<link src="assets/custom.css?version=1"></link>
At the end of my files,so the cache issue is fixed.
Another story in between is my site has some pages which has question mark in its url example,
www.mysite.com/home?login
I dont want google to crawl this page,so we decided to put a setting that all url's with question mark should not be crawl by google.So,those '?' mark url's are blocked.
Here because of this my css file is also getting blocked and crawl by the google since it has question mark in it.
SO,is there any other way to block css cahce with adding '?' random number to it.I am very happy to follow the suggestion.Thanks.

You can add timestamp behind file name, i.e, custom-1515043221.css.
Check this out : gulp-rev, it is a gulp plugin which adds random string behind file to stop it from caching.
You can also do this manually by writing gulp task,
gulpfile.js
var gulp = require('gulp');
var imagemin = require('gulp-imagemin');
var htmlmin = require('gulp-htmlmin');
var replace = require('gulp-replace');
var rename = require("gulp-rename");
var timestamp = (new Date()).getTime();
gulp.task('default', ['add-timestamp', 'rename']);
// add timestamp behind files in index.html
gulp.task('add-timestamp', function () {
gulp.src(['index.html'])
.pipe(replace('style.min', 'style.min-' + timestamp))
.pipe(gulp.dest('build/'));
});
// append timestamp behind files in build
gulp.task('rename', function () {
gulp.src(['build/css/*.css'])
.pipe(rename(function (path) {
if (path.basename === 'style.min') {
path.basename += '-' + timestamp;
}
}))
.pipe(gulp.dest(function (file) {
return file.base;
}));
});
Then run this gulpfile using gulp command

Related

Normalize file path in JavaScript front-end

The short story:
Is there simple way to normalize file path in JavaScript, like in Java we have Paths.get("/a/b/../c").normalize() so /a/../../c would become /c. I seen many same questions here, but they are Node.js solutions, and I need pure JS or JQuery approach so it can be used in browser.
The long story:
I have a file server with web UI, that allows to browse files and download them. UI is written in spring and accessible at mysite.com/ui/
The file storage located at mysite.com/files/ which is plain Apache directory, so its possible to get direct link to file.
The real storage directory on server is /var/www/files
Path passing to back-end as mysite.com/ui/?path=/a/../../c, so back-end will normalize path variable separately to /c and then append it to base dir and so retrieving content of /home/storage/c, so it works perfectly.
The problem comes when user tries to download file like this with direct link. I.e. if user tries to download /a/../../c/d file from file server root, it appending to base storage url, which mysite.com/files/, and it becomes mysite.com/files/a/../../c/d so it will point to /var/www/d instead of /var/www/files/d so file can't be downloaded even if it is visible from web UI.
So I need to normalize relative file path first on front-end like on back-end when retrieving content of directory but I don't know how it can be done in JS. Is there function for it, or I have to write my own one?
So I ended up writing my own function on JS. It might be not what "path normalization" stands for, but anyway its exactly what I need
function normalizePath(path) {
// remove multiple slashes
path = path.replace(/\/+/g, '/');
// remove leading slash, will be added further
if (path.startsWith("/"))
path = path.substring(1)
// remove trailing slash
if (path.endsWith("/"))
path = path.slice(0, -1);
let segments = path.split("/");
let normalizedPath = "/";
for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex++) {
if (segments[segmentIndex] === "." || segments[segmentIndex] === "") {
// skip single dots and empty segments
continue;
}
if (segments[segmentIndex] === "..") {
// go up one level if possible
normalizedPath = normalizedPath.substring(0, normalizedPath.lastIndexOf("/") + 1);
continue;
}
// append path segment
if (!normalizedPath.endsWith("/"))
normalizedPath = normalizedPath + "/"
normalizedPath = normalizedPath + segments[segmentIndex];
}
return normalizedPath;
}
Still, I won't mark this as accepted answer as it's more of a quick fix, and I'm not JS expert so it definitely must be more elegant solution.

Ionic 3 Prod Build With Version Number

I use the following command when building an ionic project for desktop
ionic cordova build browser --prod
Which results in the following file being generated
build/main.js
However I would like to be able to add a version number to the generated file automatically as part of the build process. So would end up with something like
build/main.js?version=1.00
as to avoid needing to clear the browser cache after every prod build.
Is there a flag for this, or is it something I must do manually?
Any advice would be great!
EDIT:
My solution is on GitHub for anyone interested!
https://github.com/RichardM99/ionic-3-version-build-file-hook
Here's some advice - You can create a cordova hook.
Hooks are scripts that you want to be executed at different stages of the build process. In your case, you are looking at a script which renames the main.js file after the build event is finished, or in other words a 'after_build' type hook.
The script will usually be a Node.js file, although you can have other types of scripts executed as well.
One more thing. Since you want to get around cache, you wont be renaming the file itself. What you will want to do is rather replace the reference to "main.js" in you "index.html" to include a random or maybe your actual version number.
I have pointed you in a direction, but won't spoonfeed. Look up documentation on cordova hooks. They are super simple if you understand Javascript/Node
Something like this should get the job done:
var index_orig = fs.readFileSync(path-to-index.html, 'utf8');
var index_new = index_orig.replace("main.js", "main.js?version="+version_num);
fs.writeFileSync(path-to-index.html, index_new, 'utf8');
If you want the actual build number, you can read your config.xml and parse it to get it's value.
Hope it helps.
I wrote blog long time ago
In my build pipeline i have command to set version
version "$(app.versionPrefix)$(Build.BuildNumber)"
$(app.versionPrefix) - is a prefix version such as 0.1.
$(Build.BuildNumber) - is build version
Then I have environment file
export const environment = {
apiUrl: 'https://....',
production: true,
version: '0.0.57'
}
Then i have js script to update version in environment and config.xml
var replace = require('replace-in-file');
var package = require("./package.json");
var buildVersion = package.version;
const options = {
files: ['config.xml'],
from: /" version="([0-9]*.[0-9]*.[0-9]*)"/g,
to: "\" version=\""+ buildVersion + "\"",
allowEmptyPaths: false,
};
const optionsEnv = {
files: ['src/environments/environment.prod.ts'],
from: /version: '(.*)'/g,
to: "version: '"+ buildVersion + "' ",
allowEmptyPaths: false,
};
try {
let changedFiles = replace.sync(options);
if (changedFiles == 0) {
throw "Please make sure that file '" + options.files + "' has \"version: ''\"";
}
changedFiles = replace.sync(optionsEnv);
if (changedFiles == 0) {
throw "Please make sure that file '" + optionsEnv.files + "' has \"version: ''\"";
}
console.log('Build version set: "' + options.to + '"');
}
catch (error) {
console.error('Error occurred:', error);
throw error
}
NOTE: you need to install plugin replace-in-file
Then in build pipe line I am running this script
node ./replace.build.js
In your case if you need only for browser you can tune script.

store and access image file paths when templating (from cloudinary or other service)

I’m using gulp and nunjucks to automate some basic email templating tasks.
I have a chain of tasks which can be triggered when an image is added to the images folder e.g.:
images compressed
new image name and dimensions logged to json file
json image data then used to populate template when template task is run
So far so good.
I want to be able to define a generic image file path for each template which will then concatenate to each image name (as stored in the json file). So something like:
<img src="{{data.path}}{{data.src}}" >
If I want to nominate a distinct folder to contain the images for each template generated then cloudinary requires a mandatory unique version component to be applied in the file path. So the image path can never be consistent throughout a template.
if your public ID includes folders (elements divided by '/'), the
version component is mandatory, (but you can make it shorter. )
For example:
http://res.cloudinary.com/demo/image/upload/v1312461204/sample_email/hero_image.jpg
http://res.cloudinary.com/demo/image/upload/v1312461207/sample_email/footer_image.jpg
Same folder. Different path.
So it seems I would now need to create a script/task that can log and store each distinct file path (with its unique id generated by cloudinary) for every image any time an image is uploaded or updated and then rerun the templating process to publish them.
This just seems like quite a convoluted process so if there’s an easier approach I’d love to know?
Else if that really is the required route it would great if someone could point me to an example of the kind of script that achieves something similar.
Presumably some hosting services will not have the mandatory unique key which makes life easier. I have spent some time getting to know cloudinary and it’s a free service with a lot of scope so I guess I'm reluctant to abandon ship but open to all suggestions.
Thanks
Note that the version component (e.g., v1312461204) isn't mandatory anymore for most use-cases. The URL could indeed work without it, e.g.,:
http://res.cloudinary.com/demo/image/upload/sample_email/hero_image.jpg
Having said that, it is very recommended to include the version component in the URL in cases where you'd like to update the image with a new one while keeping the exact same public ID. In that case, if you'd access the exact same URL, you might get a CDN cached version of the image, which may be the old one.
Therefore, when you upload, you can get the version value from Cloudinary's upload response, and store it in your DB, and the next time you update your image, also update the URL with the new version value.
Alternatively, you can also ask Cloudinary to invalidate the image while uploading. Note that while including the version component "busts" the cache immediately, invalidation may take a while to propagate through the CDN. For more information:
http://cloudinary.com/documentation/image_transformations#image_versions
This is the solution I came up with. It's based on adapting the generic script I use to upload images from a folder to cloudinary and now stores the updated file paths from cloudinary and generates a json data file to publish the hosted src details to a template.
I'm sure it could be a lot better semantically so welcome any revisions offered if someone stumbles on this but it seems to do the job:
// points to the config file where we are defining file paths
var path = require('./gulp.path')();
// IMAGE HOSTING
var fs = require('fs'); // !! not installed !! Not required??
var cloudinary = require('cloudinary').v2;
var uploads = {};
var dotenv = require('dotenv');
dotenv.load();
// Finds the images in a specific folder and retrurns an array
var read = require('fs-readdir-recursive');
// Set location of images
var imagesInFolder = read(path.images);
// The array that will be populated with image src data
var imgData = new Array();
(function uploadImages(){
// Loop through all images in folder and upload
for(var i = 0; i < imagesInFolder.length;i++){
cloudinary.uploader.upload(path.images + imagesInFolder[i], {folder: path.hosted_folder, use_filename: true, unique_filename: false, tags: 'basic_sample'}, function(err,image){
console.log();
console.log("** Public Id");
if (err){ console.warn(err);}
console.log("* Same image, uploaded with a custom public_id");
console.log("* "+image.public_id);
// Generate the category title for each image. The category is defined within the image name. It's the first part of the image name i.e. anything prior to a hyphen:
var title = image.public_id.substr(image.public_id.lastIndexOf('/') + 1).replace(/\.[^/.]+$/, "").replace(/-.*$/, "");
console.log("* "+title);
console.log("* "+image.url);
// Add the updated src for each image to the output array
imgData.push({
[title] : {"src" : image.url}
});
// Stringify data with no spacing so .replace regex can easily remove the unwanted curly braces
var imgDataJson = JSON.stringify(imgData, null, null);
// Remove the unwanted [] that wraps the json imgData array
var imgDataJson = imgDataJson.substring(1,imgDataJson.length-1);
// Delete unwanted braces "},{" replace with "," otherwise what is output is not valid json
var imgDataJson = imgDataJson.replace(/(},{)/g, ',');
var outputFilename = "images2-hosted.json"
// output the hosted image path data to a json file
// (A separate gulp task is then run to merge and update the new 'src' data into an existing image data json file)
fs.writeFile(path.image_data_src + outputFilename, imgDataJson, function(err) {
if(err) {
console.log(err);
} else {
console.log("JSON saved to " + outputFilename);
}
});
});
}
})();
A gulp task is then used to merge the newly generated json to overide the existing json data file:
// COMPILE live image hosting data
var merge = require('gulp-merge-json');
gulp.task('imageData:comp', function() {
gulp
.src('src/data/images/*.json')
.pipe(merge('src/data/images.json'))
.pipe(gulp.dest('./'))
.pipe(notify({ message: 'imageData:comp task complete' }));
});

Finding a Relative File Path to Parse an Excel File

I'm building a web app using Node.JS that at the very least should allow users to to upload excel spreadsheets (.xlsx) and then using an excel parser (currently using node-xlsx - https://www.npmjs.org/package/node-xlsx), I want to be able to find this file, parse it, and print its contents to the console. So far, I have the file uploaded and stored, but am having trouble specifying the file path my app should search down.
I believe my troubles are that I am trying to do this on the server-side, and I am telling my app to search through a users directory for this file when it does not have access.
Here is example code:
var fullfile;
app.post('/upload', function (request, response) {
var fstream;
request.pipe(request.busboy);
request.busboy.on('file', function (fieldname, file, filename) {
console.log('Uploading: ' + filename);
fstream = fs.createWriteStream('./storedFiles/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
response.redirect('success');
console.log('Uploaded to ' + fstream.path);
fullfile=fstream.name;
var obj = xlsx.parse(__dirname + fullfile);
console.log(obj);
});
});
});
This produces the error:
return binding.open(pathmodule._makelong(path) stringtoflags(flags) mode)
error: ENOENT, no such file or directory 'C\Users(file path on my local machine here)
Can anyone point out a way of doing this that I am missing? it has to do with fs methods I feel.
Thank you
First of all, don't use the filename that user provided when saving the file - you will get duplicates and it could be a security risk (in general, never trust user provided data). Just use your own value instead - it is more standard to use your own naming convention to prevent duplicates or to use a tmp file provided by the OS.
To solve your issue, try:
Requiring path at the top of your file:
var path = require('path');
and changing the value of fullfile to:
fullfile = path.join(__dirname,fstream.path)
then pass fullfile to xlsx.parse:
var obj = xlsx.parse(fullfile);

iOS Phonegap Media Object - How do I access a resource in the WWW folder?

I'm developing an application with phonegap, and I have a sound file I want to play that's in a path like so www/Sounds/sound.mp3, and I'm trying to access this file using the Media object of Phonegap in order to play it.
I cannot figure out the path to access this sound file within a javascript file that uses the Media object? I've tried paths like, file:///www/Sounds/sound.mp3, relative paths, etc and I cannot access it. I keep getting the following error in xcode 4
Will attempt to use file resource 'file:///www/Sounds/sound.mp3'
Unknown resource 'file:///www/Sounds/sound.mp3'
What path do I need to use to access the file? Or do I need to copy the sound file out of my www directory and into my Resources folder and access it there?
My WWW folder is referenced, not sure if that makes a difference.
Heres a modified version of getPhoneGapPath that works for me on both iOS and Android. It is also not restricted to only working on files that have a filename that is 10 characters long :)
getPhoneGapPath: function () {
'use strict';
var path = window.location.pathname;
var phoneGapPath = path.substring(0, path.lastIndexOf('/') + 1);
return phoneGapPath;
}
var resource = getPhoneGapPath() + 'audio/audio.mp3';
getPhoneGapPath() will return:
iOS: /var/mobile/Applications/{GUID}/{appName}/www/
Android: /android_asset/www/
Use window.location.pathname to get the path of your application. It will look something like this on iPhone:
/var/mobile/Applications/{GUID}/{appname}.app/www/index.html
And this on Android:
/android_asset/www/index.html
Strip off the /index.html, prepend file://, and append your relative path Sounds/sound.mp3.
Here's something to get you started:
Demo: http://jsfiddle.net/ThinkingStiff/chNVY/
Code:
function getPhoneGapPath() {
var path = window.location.pathname;
path = path.substr( 0, path.length - 10 );
return 'file://' + path;
};
var resource = getPhoneGapPath() + 'Sounds/sound.mps';
The best answer is outdated. You are now able to play wav, mp3, and caf formats on iOS using this "relative path" method:
var media = new Media('beep.wav', ...);
Note that the above code requires the sound file to be in the root of your www/ directory -- in this example at www/beep.wav. If you want to put them in a subdiretory like www/sounds/, you'll need to specify it using a path relative to your www/ directory. For example, this also works now:
var media = new Media('sounds/beep.wav', ...);
for the sound file at www/sounds/beep.wav.
As of Cordova 3.3+, the 2 other answers aren't correct. It should work even if you just pass it a file name.
But, it will only work in iOS if the file extension is .wav.
This will work:
var media = new Media('recording.wav', ...);
This won't:
var media = new Media('recording.mp3', ...);
I had the same problem and all the answers about file paths alone didn't work for me using the Phone Gap Developer app. The problem was with the Developer app not pushing the files physically onto the device, preventing me from accessing them in any way.
The Media plugin worked as intended using
$ phonegap run android
$ phonegap run ios
with this js code:
function getPhoneGapPath() {
var path = window.location.pathname;
var phoneGapPath = path.substring(0, path.lastIndexOf('/') + 1);
return phoneGapPath;
}
var sound = new Media(getPhoneGapPath()+"assets/sounds/sound.mp3"
//...
sound.play();
This returns an error on Developer app:
'Cannot use audio file from source var/mobile/Containers/data/Application/{GUID}/Library/NoCloud/phonegapdevapp/www/assets/sounds/sound.mp3'
but works if built from the console.
Details can be found here:
https://forums.adobe.com/thread/2135718
Better try this to take into account any HTML5 History API code that might add in history entries with directories ("/"):
function get_phonegap_path () {
var path = window.location.pathname
return path.slice(0, path.indexOf("/www/") + 5)
}

Categories

Resources