I am facing a weird problem right now. So, I am trying to test production build, and the build files generated contain a ?v=${some random number here} to prevent caching.
However, the browser-sync doesn't load these files.
The way I figured that out is because is that I have in total 3 files, 2 script files and one stylesheet. One of the script files and the stylesheet have the query string generated.
The script file that doesn't contain the query string gets loaded.
My folder structure is
/
index.html
assets/
dist/
mystyle.css?v=1237791723
myscript.js?v=123576231612
And the two gulp tasks are
gulp.task('localScripts', function() {
return gulp.src(['assets/js/app.js', 'node_modules/owl.carousel/dist/owl.carousel.min.js', 'assets/dist/js/style.js'])
.pipe(babel({ presets: ['babili'] }))
.pipe(concat(`myscript.js?v=${date}`))
.pipe(gulp.dest(dist))
})
gulp.task('joinCss', function() {
return gulp.src(['node_modules/bootstrap/dist/css/bootstrap.min.css', 'assets/dist/css/style.min.css'])
.pipe(concat(`mystyle.css?v=${date}`))
.pipe(gulp.dest(dist))
})
And one replace html task which I use to generate the build index.html is
gulp.task('replaceHtml', function () {
gulp.src('./start.html').pipe(htmlReplace({
'js': ['assets/dist/scripts.js', `assets/dist/myscript.js?v=${date}`],
'css': `assets/dist/mystyle.css?v=${date}`
})).pipe(rename('index.html'))
.pipe(gulp.dest('./'))
});
And, the final generated index.html has the desired files in place:
<link rel="stylesheet" href="assets/dist/mystyle.css?v=1508761436559">
<script src="assets/dist/scripts.js"></script>
<script src="assets/dist/myscript.js?v=1508761436559"></script>
And my browser-sync config is
gulp.task('server', [], function() {
browserSync.init({
server: {
baseDir: "./"
},
port: 9001,
});
});
And when I start the server, only scripts.js gets loaded.
Can anyone explain why?
I am using the latest version of browser-sync
Related
My project structure is the following:
MyApp
- hooks
- platforms
- android
- ios
- www
- js / css / templates..
- lib (including all bower components)
Right now, the www/lib directory is taking up 21,8 Mb. (I have a large set of bower components added to my project.)
When building each project, the entire www folder is copied to the platform/android (for instance) folder for build, including of course www/lib.
This leads to a very big build, as lots of files included into bower
components are useless for production.
Manually managing all bower dependencies is clearly not an option. So how do you guys manage to clean your project platform directory for build?
I was thinking about creating a hook for that but before writing lines of code in a language that i do not know (nodeJS), I was hoping for your return and advises.
According to Cordova workflow you can add a hook script that removes unnecessary files.
A detailed example of a cleanup script can be found here: https://www.thepolyglotdeveloper.com/2015/01/hooks-apache-cordova-mobile-applications/
But to give a quick step by step summary:
Add to the after_prepare hook folder (/hooks/after_prepare) a script (01_junk_cleanup.js - 01 to be run first, the rest whatever you want) and in the file specify the files and folders you want to delete. For example, here is how you can delete a test folder and relevant files just change to you lib directory and to the files there. Note that this example is a bit different from the example in the link i gave earlier so you might want to take a look there as well.
01_junk_cleanup.js:
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var foldersToProcess = [
"js",
"css"
];
var foldersToDelete = [
"test"
];
var filesToDelete = [
"karmaOnBrowser.conf.js",
"karmaOnEmulators.conf.js",
"SpecRunner.html"
];
var iosPlatformsDir = "platforms/ios/www/";
var androidPlatformsDir = "platforms/android/assets/www/";
filesToDelete.forEach(function(file) {
var filePathIOS = iosPlatformsDir + file;
var filePathAndroid = androidPlatformsDir + file;
if(fs.existsSync(filePathIOS)){
fs.unlinkSync(filePathIOS);
};
if(fs.existsSync(filePathAndroid)){
fs.unlinkSync(filePathAndroid);
};
});
foldersToProcess.forEach(function(folder) {
processFiles(iosPlatformsDir + folder);
processFiles(androidPlatformsDir + folder);
});
foldersToDelete.forEach(function(folder) {
deleteFolderRecursive(iosPlatformsDir + folder);
deleteFolderRecursive(androidPlatformsDir + folder);
});
function deleteFolderRecursive(path){
if( fs.existsSync(path) ) {
fs.readdirSync(path).forEach(function(file,index){
var curPath = path + "/" + file;
if(fs.lstatSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
}
function processFiles(dir) {
fs.readdir(dir, function(err, list) {
if(err) {
console.log('processFiles err: ' + err);
return;
}
list.forEach(function(file) {
file = dir + '/' + file;
fs.stat(file, function(err, stat) {
if(!stat.isDirectory()) {
switch(path.basename(file)) {
case ".DS_Store":
fs.unlink(file, function(error) {
console.log("Removed file " + file);
});
break;
case "Thumbs.db":
fs.unlink(file, function(error) {
console.log("Removed file " + file);
});
break;
default:
console.log("Skipping file " + file);
break;
}
}
});
});
});
}
Aside to above, A bit more obvious but I feel worth mentioning anyhow, After having the www/lib bloat as well I always try to keep the folder lean and add only libraries required for deployment, the other dev. dependencies such as jasmine I either hold in the 'node_modules' folder or 'bower_components' as I only install today through them.
Hope this helps,
Good luck
I think the best approach would be to do this:
Move the bower_components folder and your index.html file to the project root, outside the /www folder
Install gulp and gulp-usemin
Wrap all of the .js files and .css files from bower components in usemin <build:js> and <build:css> sections
Configure a task in your gulpfile to concatenate all those files into a lib.js and a lib.css file. Make sure that those two files as well as the rewritten index.html are output to the /www folder
Execute the gulp task before your next build, and each time you add a new bower component.
This will keep your /www folder tidy and only containing the files you need in your cordova build.
With Bower you need to use npm preen to remove unnecessary files
See my example using Gulp with Ionic Framework: https://github.com/jdnichollsc/Ionic-Starter-Template
Basically you can set your bower.json file to indicate the path which files you need, for example:
"preen": {
//... More libraries
"ionic-datepicker": [
"dist/*.js" //You only need these files
//Other files and folders will be deleted to reduce the size of your app
],
"ion-floating-menu": [
"dist/*" //Keep all the files (.html, .css, .js, etc) of the directory.
]
}
Regards, Nicholls
This is an improvement over this answer. I've applied it to my own project.
Move the bower_components folder to the project root, outside the www folder.
Rename index.html to _index.html. We will later make sure that Gulp automatically generates index.html.
Install gulp and gulp-useref.
Edit your _index.html so that it looks something like this:
<!-- build:js dist/js/vendor.js -->
<script src="../bower_components/ionic/release/js/ionic.bundle.min.js"></script>
<script src="../bower_components/ngstorage/ngStorage.min.js"></script>
<script src="../bower_components/ngCordova/dist/ng-cordova.min.js"></script>
<!-- endbuild -->
Configure your gulp watch task to build new index.html file in the www folder with the concatenated files.
var entrypoint = './www/_index.html';
gulp.task('watch', function() {
gulp.watch(entrypoint, ['concat-js-and-css']);
});
gulp.task('concat-js-and-css', function () {
return gulp.src(entrypoint)
.pipe(useref())
.pipe(rename(function (path) {
// rename _index.html to index.html
if (path.basename == '_index' && path.extname == '.html') {
path.basename = "index";
}
}))
.pipe(gulp.dest('./www'))
});
gulp.task('build', ['concat-js-and-css']);
When that task runs, your index.html file will contain just this:
<script src="dist/js/vendor.js"></script>
Edit your ionic.project file so that it looks like the following. This will make sure that gulp watch is run before ionic serve.
{
"watchPatterns": [
"www/_index.html",
],
"gulpStartupTasks": [
"watch"
]
}
I'm trying to wrap my head around using Grunt, usemin 2, requirejs, and uglify. What I'm observing in my builds is that requirejs is not properly including my dependencies into my single concatenated build file. When I run index.html out of /dist, I see errors when looking for 'jquery', 'app', and some third party js files or sometimes "define is not defined".
I read the following issues on grunt-usemin and removing the require blocks, but some questions still remain in those threads.
Recommended way to handle RequireJS, concat, uglify
How to handle requirejs in v2.0
I followed up my search and came across this post How to integrate Yeoman and Requirejs, which sort of got me there in that I saw the Requirejs optimizer running when I changed from using grunt-contrib-requirejs to grunt-requirejs. Unfortunately, I still see these errors:
Uncaught ReferenceError: define is not defined.
I have the following in my index.html:
<!-- build:js js/main.js -->
<script src="bower_components/requirejs/require.js"></script>
<script src="js/main.js"></script>
<!-- endbuild -->
Here is my Grunt file: http://jsbin.com/futocusu/3/edit?js
There was talk in issue #112 about creating an article on using Yeoman on this topic, but I don't think it's been written yet.
Has anyone figured out the best way to use usemin v2 with grunt and requirejs to output to a single concat+uglify file on build? I'm also not sure what the difference is in using grunt-contrib-requirejs and grunt-requirejs and when to use which one.
It looks as though you are trying to do too much with main.js.
I have the following build tasks in Gruntfile.js
grunt.registerTask('build', [
'copy', // copies the src directory to dist (htdocs)
'requirejs', // do an r.js build to concat modular dependencies
'concat:head', // concats js in the head
'uglify:head', // compresses js in the head
'uglify:foot', // compresses js in the foot
'cssmin', // minifies and concats css
'usemin', // runs through html and inputs minified js and css
'clean:afterBuild' // deletes files that are not required for build
]);
Here are each of the relevant Grunt tasks (for me these are stored in separate files because I use load-grunt-config). If you would like to use these in your gruntfile then all you need to do is grab everything that is in the returned object and stick that in your task value in your gruntfile:
copy
module.exports = function (grunt, options) {
return {
main: {
cwd: 'src/',
src: '**',
dest: 'dist/',
expand: true,
flatten: false
},
};
};
requirejs
module.exports = function(grunt, options) {
return {
compile: {
options: {
appDir: "src/to/require/app",
baseUrl: "./",
mainConfigFile: "src/to/require/app/common",
dir: "dist/to/require/app",
// build a common layer
modules: [
{
"name": "common"
}
]
}
}
};
};
concat
module.exports = function (grunt, options) {
return {
head: {
/* other stuff */
},
foot: {
src: [
'dist/to/require/app/some_other_js.js',
'dist/to/require/app/external/require.js',
'dist/to/require/app/external/require.text.js',
'dist/to/require/app/common.js'
],
dest: 'src/to/require/app/compiled_footer_js.js',
}
};
};
uglify
module.exports = function (grunt, options) {
return {
head: {
/* other stuff *
},
foot: {
files: {
'src/to/require/app/compiled_footer_js.min.js': ['src/to/require/app/compiled_footer_js.js']
}
}
};
};
usemin
module.exports = function (grunt, options) {
return {
html: [
'src/path/to/index.html'
]
};
};
How should one package the HTML templates (aka 'partials') in an Angular.js app when it is concatenated + minified for distribution? Is there a good way of including them in that single file, or should I zip the folder which contains the main.js, /templates/*.html and /styles/app.css subdirectories?
The Require.js optimizer compresses all the JS files to a single file myapp.min.js that is suitable for distribution, but the HTML files are still referenced as individual files.
As background, the code is in a Node.js server:
public/
/app/main.js
/app/app.js
/app/directives/*.js
/app/filters/*.js
/app/factories/*.js
/app/other/*.js
/app/templates/*.html
After running r.js, all the files in public/app/** have optimized twins located in a different directory public/build/**. But the browser still looks for the templates in their original location, /app/templates/*.html.
So presumably the client would have to put them in that same directory, which seems like an unfair constraint.
Minifying RequireJS Javascript codebase to a single file
You have to use the templates through the text! plugin of RequireJS. E.g. for a directive:
define(["text!app/templates/a.html", "myAngularModule"],
function(template, myAngularModule) {
myAngularModule.directive("theDirective", function() {
return {
template: template, // NOTE HERE
...
};
});
});
Or a route:
define(["text!app/templates/a.html", "myAngularModule"],
function(template_a, myAngularModule) {
myAngularModule.config(function($routeProvider) {
$routeProvider.when("some/path", {
template: template_a, // NOTE HERE
...
});
...
});
});
Alternative, using templateUrl (just in case it is needed):
define(["text!app/templates/a.html", "myAngularModule"],
function(template_a, myAngularModule) {
myAngularModule.config(function($routeProvider) {
$routeProvider.when("some/path", {
templateUrl: "app/templates/a.html", // can be any value actually
...
});
...
});
myAngularModule.run(function($templateCache) {
$templateCache.put(
"app/templates/a.html", // NAME MUST MATCH NAME ABOVE
template_a
);
});
});
I have the following simple structure:
index.html
...
<script src="static/js/lib/require.js" data-main="static/js/main"></script>
</head>
...
static/js/main.js
requirejs.config({
baseUrl: 'static/js',
paths: {
m: 'modules'
}
});
require(['m/test01'], function(test01) {
console.log(test01.print());
});
static/js/modules/test01.js
define(['m/test02'], function(test02){
return {
print: function() {
return 'test01 and '+ test02;
}
};
});
static/js/modules/test02.js
define(function() {
return 'test02';
});
Now when I open index.html directly (file:///index.html) all goes well. The script loading works and "test01 and test02" is logged in the console.
However, if I'm opening via xampp (localhost/requiretest/index.html) the loading of test01.js goes well, but for test02.js I get this error in the console (Firefox):
NetworkError: 404 Not Found - localhost/01-test-grunt/static/js/test02.js
(removed "http://" before localhost for stackoverflow)
As you can see the 'modules/' part is missing in the URL.
Anyone got any idea what might be going on?
NOTE: It does work when I change baseUrl to 'static/js/modules', but I can't do this because of my grunt buildprocess. Anyway, I assume other paths won't be loaded either, so is this a bug or am I doing something wrong?
I am using requirejs for a multipage application. I am having a weird issue with the order of execution of the main files. Here is my setup.
In all of my html pages ( This main has all the common js files that are required by all my pages)
then on each page (say page1.html):
<script data-main="main" src="require.js" />
<script>
require(['require','main'],function(require) {
require(['main-library']);
});
</script>
My main.js looks like:
require.config({
paths:{
'lib':'../lib',
'jquery': '../lib/jquery/jquery-1.7.1.min',
'jquery.iframe-transport' : '../lib/jquery.iframe-transport.min.js'
},
deps:['jquery','jquery-ui'],
shim: {
<other shim files>
},
});
require([<list of all other dependencies>], function() {
});
And the main-library.js looks like:
define('main-library',
['main',
'jquery.iframe-transport',
<other dependencies>
],
function() {
}
);
My expectation:
Was that the "main-library" will not start to load until the "main" and all the dependencies specified in the main are not loaded. I expect this since I require "main-library" in a nested require call on each page. see above.
The issue:
When my page1.html loads, it looks like the main-library.js starts loading even before the main.js has finished loading and main-library fails to get the require.config and hence the paths for the dependencies are not seen by it.
What am I doing wrong ?
Answering my own question. It was infact another require down in that page1.html that was loading the "main-library" again. So I had something like:
<script data-main="main" src="require.js" />
<script>
require(['require','main'],function(require) {
require(['main-library']);
});
</script>
...
... Other html ...
...
<script>
require(['main-library'],function(require) {
//do something.
});
</script>
This second require on main-library was the one that was failing to find the paths. Wrapping it with a require on main worked.