Watching multiple "file arrays" in gruntjs - gruntjs

So in my config file, I'm statically defining the css files to watch, along with some html partials. (eventually I will minimatch with exclusions .. I'm just going with first pass right now)
Originally I was storing these in the grunt config object, but struggled to get the output I wanted, so I moved them out of the initConfig method and into the wrapping function:
Original pass:
grunt.initConfig({
cssFiles: [ ... list of files ... ],
htmlFiles: [ ... list of files ...],
watch: {
reload: {
files: ['<%= cssFiles.concat(htmlFiles).join(",") %>']
}
}
});
I tried several variations of this (with and without join), as an example.
Current "Working" version:
module.exports = function(grunt) {
var cssFiles = ['someFile.css',...'lastFile.css'],
htmlFiles = [ ... ];
grunt.initConfig({
watch: {
reload: {
files: cssFiles.concat(cshtmlFiles)
}
}
});
};
I feel like I should be able to do this without having to move my array's out of the grunt config (although I don't know WHY I feel they should stay there ... I guess I just haven't seen many Gruntfile's with code outside of initconfig)

I'm using a system that stores all the paths I need in a single config object, like so:
grunt.initConfig({
pathTo: {
distcss : './dist/css/master.css',
srcstyles : './lib/styles/**/*.scss',
vendor : './lib/vendor'
},
// tasks...
});
Then, I load those in via underscore templates like in your first example. If your project is structured in a good way then usually just having one minimatch pattern is enough. All my CSS ends up in lib/styles, and any misc. third party stuff is usually in lib/vendor as that is managed through Bower.
With the right directory structure and pattern you shouldn't need a large array of paths. A sample JavaScript project could look like this:
lib
└── src
├── app
└── tests
Then your minimatch pattern to lint your application and test code would just be lib/src/**/*.js, for example.
But what works for you works for you; if you've written a system that you're happy with, regardless of whether you've seen it elsewhere or not, there's no reason to change it. :-)

Related

Grunt , Babel setup for Es6 with external helper

Hi there I have been forced to come here due to every resource out there on the topic is very poor and incomplete.
Not only on the babel site but every single post out there is not complete and informative enough.
I tried to reach out at the babel forum and no replies.
I am trying to convert my prototype libraries to Es6 and convert to the most leanest possible code. So no bloaty duplicated generated code and if possible no bloaty requirejs and whatever browserify generates.
I have tried to make a project with grunt and babel directly, configure the external-helpers plugin according to the babel documentation.
It fails to include the relevant helper code and fails to include the import module code altogether.
ie a babel config like
{
options: {
sourceMap: false,
presets: ['es2015'],
"plugins": ["external-helpers"]
},
dist: {
files: {
'build/<%= package.name %>.js': ['src/<%= package.name %>.js']
}
}
}
The main project file has an import like
import Button from './ui/buttons/Button';
The module code looks like this as if the export is placed underneath extra code is generated for that.
export default class ShareButton {}
produces an output like this
Object.defineProperty(exports, "__esModule", {
value: true
});
require('babel-core/external-helpers');
var _Button = require('./ui/buttons/Button');
var _Button2 = babelHelpers.interopRequireDefault(_Button);
No source of the module or the helper object is included.
I searched hard for how to deal with external-helpers and it suggests it has to be imported into a separate file ie something like this to generate only the helper functions needed
babel-external-helpers -l createClass > src/helpers.js
But any resource regards to this fails to go as far as to how to import that into the project.
If I use the transform-runtime plugin, it produces a massive polyfill that cannot be disabled so a bug and not so useful for what I need.
"plugins": [
["transform-runtime", { "polyfill": false, "regenerator": false }]
]
If I use browserify / babelify it makes a royal mess and duplicates code still.
A config like
{
options: {
"transform": [["babelify", {
"presets": ["es2015"],
"plugins": ["external-helpers"],
sourceMap: false
}]]
},
dist: {
files: {
'build/<%= package.name %>.js': ['src/<%= package.name %>.js']
}
}
}
Produces code like this still with the external helper missing and duplicated code not relevant to the helper. ie
Object.defineProperty(exports, "__esModule", {
value: true
});
Is within every module in the generated file.
If I export the classes like this at the bottom of every file
export default class {}
Duplicated code is generated like
var _class = function _class() {
babelHelpers.classCallCheck(this, _class);
};
exports.default = _class;
In terms of filesize that doesn't include bloaty wrapping code like
},{}],2:[function(require,module,exports){
It seems concatting all the prototype classes files together to bundle in one file is the winner still.
So trying to port the library but keep it similar and bundle it together into one file.
Hopefully this is concise enough and there is a simple solution.
FYI browsers do not understand tabs and 4 spaces. I had to edit this post in my editor to get the code blocks working ! It would be nice to have a markup like other places like "```" ?
Let me know thanks.
I'm using rollup with babel now. Rollup produces a clean output as umd mode. Browserify is really bloaty in itself.
There is just a problem with polyfills being converted. I have to concat external ones in like for WeakMap.
I had a problem trying to use the generated Iterator and finding a polyfill for that so I have to code loops a particular way it doesn't generate Iterators.
The polyfill generation in babel is still too bloaty and crazy. It's pretty terrible. So I concat in minified polyfills that are very small and it's used globally.
I was running into something very similar. Was tired of trying to do it the "right way" and ended up just creating https://www.npmjs.com/package/grunt-babel-helpers which simply manipulates the string output.

Using grunt-manifest to generate appcache manifests with relevant paths based on the root

I have a number of backbone apps all hosted on the same site. I am attempting to use grunt-manifest to generate appcache manifests for them. It generates the manifest file, but the links are wrong. I want each app to have a separate manifest file.
For example say I have an app called 'hello', it would be accessed via this url:
mydomain.com/apps/hello
so the main js and css files would be at:
mydomain.com/apps/hello/app.js
mydomain.com/apps/hello/style.css
etc.
There are also some shared components, found at say:
mydomain.com/shared/shared.js
(I dynamically load these with require.js so don't want to concat into the main app.js)
I specify the manifest in grunt like this:
manifest: {
generate: {
options: {
basePath: '<%= gconf.dist_dir %>/',
timestamp: true,
network: ['*'],
},
files: [
{
cwd: 'public/',
src: [
'apps/hello/*',
'shared/*',
// etc
],
dest: '<%= gconf.dist_dir %>/public/apps/hello/manifest.appcache' },
]
}
},
I believe the issue is I am trying to get grunt-manifest to generate an appcache manifest for a portion of a site not the root site. The manifest i get looks like this:
CACHE
apps/hello/app.js
apps/hello/style.css
shared/shared.js
When I load the page - the manifest retrieval fails because it is trying to access links like this:
mydomain.com/apps/hello/apps/hello/app.js
If I manually edit the manifest files and add a '/' in front of everything so it looks like this:
CACHE
/apps/hello/app.js
/apps/hello/style.css
/shared/shared.js
...then it all works.
The issue obviously being the manifest creating relative links, when I want them from the root.
I cannot for the life of me figure out how to get grunt-manifest to create these for me with a '/' in front.
I've tried experimenting with 'basePath' on its own, 'cwd' on its own, a combination of the two. If I leave the '/' off the end of say basePath or cwd and try adding it in the 'src' it doesn't work and I get an empty CACHE section.
I'm sure there must be an easy way of doing this with the grunt globing patterns, but I just can't work it out.
Any ideas?
(also - not enough rep to create a new tag, but a 'grunt-manifest' tag might be useful for others in the future)
I just ecnountered the same issue.
I've forked the module here: https://github.com/killfish/grunt-manifest
If you pass in the option absolutePath : true, it will prepend a '/'
options: {
**absolutePath: true,**
network: ['http://*', 'https://*'],
preferOnline: true,
verbose: true,
timestamp: true
},

Grunt cssmin rebasing a relative URI?

I'm currently setting up grunt-usemin for our project but I'm running in a small issue with the cssmin task.
Our project depends on a few external libraries, some which bring a long some extra assets (like images or fonts). The problem is these libraries do not have the same folder structure.
This is an example of the different folder structures
lib
|--lib1
| |--style1.css
| +--image1.png
+--lib2
|--styles
| +--style2.css
+--images
+--image2.png
In the index.html all the stylesheets are referenced and put inside a build block. As such, when the usemin task executes, the stylesheets of the libraries are concatenated in one minified file and put inside the output folder. The corresponding assets (images) are copied over to this output folder as well and flatened in the img folder. The output folder structure looks like
out
|--allstyles.min.css
|--image1.png
+--image2.png
As you can guess, the concatenated stylesheets has (in this example) two different relative URIs:
image1.png
..\images\image2.png
This is causing an issue where some of the images cannot be found. I need a solution to rebase all relative URIs to the out folder. I tried using the target and root options of the cssmin task but to no avail. Could someone point me to a correct configuration of this task or to another Grunt task that could achieve what I'm looking for?
Thanks in advance!
I have a grunt file in C:\web\project and CSS files in C:\web\project\www\css. The following snippet is from my grunt file and it rebases URLs correctly for me.
var cssFiles = [
'www/css/layout/Header.css',
'www/css/layout/Footer.css',
'www/css/vendor/chosen/chosen.css'
// ...
];
cssmin: {
concat: {
options: {
keepBreaks: true, // whether to keep line breaks (default is false)
debug: true, // set to true to get minification statistics under 'stats' property (see test/custom-test.js for examples)
noAdvanced: true, // set to true to disable advanced optimizations - selector & property merging, reduction, etc.
//relativeTo: 'http://online-domain-tools.com/'
noRebase: false, // whether to skip URLs rebasing
root: 'www'
},
nonull: true,
src: cssFiles,
dest: 'www/temp/application.css'
},
minify: {
options: {},
nonull: true,
src: ['www/temp/application.css'],
dest: 'www/temp/application.min.css'
}
},
// ...
grunt.registerTask('default', ['cssmin:concat', 'cssmin:minify']);
Can you post your gruntfile to compare it?
Related reading: https://stackoverflow.com/a/21415649/99256
look in the cssmin documentation/options:
rebase: set to false to skip URL rebasing
That solves the issue.

Configure Grunt-Bower-Install path for a Component

How do I specify the default file to use for a bower component so that it will be injected properly by grunt-bower-install?
I am working with datejs and they have different files depending on your localization. The file I'm wanting to include is not in the root of bower_components/datejs directory so I get the error:
datejs was not injected in your file.
Please go take a look in
"app/bower_components/datejs" for the file you need, then manually
include it in your file.
I'm trying my hardest to avoid hardcoding datejs into my index file and don't really want to move "date-en-US.js" file into the root of the datejs directory either.
This is the structure of the datejs bower component.
bower_components
└── datejs
└── build
└── ...
└── date-en-US.js
└── ...
└── src
└── test
And just in case this helps, this is the .bower.json file that is located in the datejs bower component path:
{
"name": "datejs",
"homepage": "https://github.com/datejs/Datejs",
"_release": "7bdddb55d6",
"_resolution": {
"type": "branch",
"branch": "master",
"commit": "7bdddb55d69719e42c358c3a2b7df706ff3090f8"
},
"_source": "git://github.com/datejs/Datejs.git",
"_target": "*",
"_originalSource": "datejs",
"_direct": true
}
A little late to the party but you can override the main property of a repo to define whatever file you want to inject into your app. To do this you need to use the overrides property in YOUR bower.json.
Try this:
{
"name": "name",
"version": "x.x.x",
"dependencies": {
"datejs": "x.x.x"
},
"overrides": {
"datejs": {
"main": "build/date-en-US.js"
}
}
}
I too was frustrated by this a few times. What I found in my cases was that "grunt bower-install" requires a "main" entry in the .bower.json. It's a string or array of strings that point to the relevant JS and/or CSS files that should be installed.
In your case I do not see the "main" and would suggest you create one that contains the desired datejs files. I would suggest the source files if you intend to use grunt for minification/etc. You can look at other successful components to see examples of the "main" entry.
I suspect that some components do not supply the entry because they have no single usage pattern (i.e. you can mix and match the files you require), but this is just speculation on my part.
Try adding this in your grunt file:
'bower-install': {
fileTypes: {
fileExtension: {
detect: {
typeOfBowerFile: /-en-US.js/
}
}
}
}
I didn't try this out, and my regex might be off. But accoriding to the grunt-bower-install readme, it states See [wiredep's](https://github.com/stephenplusplus/wiredep) readme for more options of customization and there it shows using the above configuration.
Essentially - grunt-bower-install doesn't know what to look for. This option appears to tell it that info.

How to use grunt-contrib-livereload?

I'm trying to use grunt-contrib-livereload, but can't seem to figure it out. The readme seems to skip over everything that I need explained, and then ends with an example that doesn't work when I try it and doesn't seem directly related to the documentation. I have searched for a better explanation in a blog post or tutorial or whatever, but haven't been able to find one. Can someone please explain how to get started with this tool?
Here are the kinds of questions I have, based on the readme:
The documentation says the livereload task "must be passed the list of files that have changed" --- but how do I pass it this list of files? The example does not seem to illustrate this. Does regarde pass the list?
Is grunt-contrib-connect required? What does it do, and how do I use it? Do I need to learn connect before I try using livereload?
The readme mentions middleware that "must be the first one inserted" --- but inserted into what, before what else? And how is it inserted?
And I suppose I don't understand how I need to manipulate ports. "All the browsers listening on the livereload port will be reloaded" --- but how do I know which browser is listening to which port? Do I need to learn all about ports before I can try using livereload? (Any suggestion on how to best learn about that?)
Finally, in the example, there is a folderMount function that doesn't seem related to any of the documentation before. What is that, and do I need it?
I guess I'm asking if someone can please:
point me towards a tutorial that is much more effective than the current readme;
explain these unexplained parts of the readme, if those answers are what I need to understand the plugin;
or provide a functional example with some explanation of why it is functional.
Live reloading is now built into grunt-contrib-watch version 0.4.0. grunt-contrib-livereload and grunt-regarde will be deprecated soon.
Now just set the option livereload to true in your config and it will create a live reload server then reload after the tasks have run:
grunt.initConfig({
watch: {
all: {
options: { livereload: true },
files: ['lib/*.js'],
tasks: ['jshint'],
},
},
});
By default the live reload server will be started on port 35729. So to enable live reloading on your page just add <script src="http://localhost:35729/livereload.js"></script> to your page.
View more info on the docs: https://github.com/gruntjs/grunt-contrib-watch#live-reloading
Edit: Check versioning info. grunt-contrib-watch now has livereload support baked in.
What a doozy. I ran into issues with this one too so let me do what I can to explain (or at least get you up and running). Keep in mind, this is how I have it set up and it seems to work most of the time.
For starters, you'll want to make sure you've udpated your package.json with the right dependencies. I'm not sure that livereload works with the baked in "watch" task and I've been using grunt-regarde of late. My package.json usually looks like this:
"dependencies": {
"grunt": "~0.4.x",
"grunt-contrib-livereload": "0.1.2",
"grunt-contrib-connect": "0.2.0",
"grunt-regarde": "0.1.1"
},
Obvi you want grunt (duhhh), livereload, connect seems to help with mounting folders, and regarde is like grunt-watch, it just seems to work better (I forget why exactly).
You could make your package.json even better by specifying livereload in its own "devDependencies" object if you're so inclined. Now, run your good old fasioned npm install to get the goodies in your project.
Let's talk gruntfiles:
As you probably know, the gruntfile is what makes the magic happen. Somewhere towards the bottom of your gruntfile, you'll want to specify
grunt.loadNpmTasks('grunt-regarde');
grunt.loadNpmTasks('grunt-contrib-livereload');
grunt.loadNpmTasks('grunt-contrib-connect');
At the top of your gruntfile, we'll want to add some utils for livereload. Under /*global module:false*/, go ahead and add var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;.
After that, you don't really need to learn connect, you just gotta use it. Check my style:
var folderMount = function folderMount(connect, point) {
return connect.static(path.resolve(point));
};
This comes before module.exports = function(grunt) {
Now let's get into the meat of the gruntfile. Again, I forget what connect is doing but this is where the middleware magic comes into play. In your modules.exports, add:
connect: {
livereload: {
options: {
port: 9999,
middleware: function(connect, options) {
return [lrSnippet, folderMount(connect, '.')]
}
}
}
},
Now we want to have the files watched. I like to set up a few different tasks since I don't want my whole grunt process running every time I save a CSS file. Here's what I work with (again, add to module.exports):
regarde: {
txt: {
files: ['styles/*.css', 'index.html'],
tasks: ['livereload']
},
styles: {
files: ['sass/*.scss', 'sass/*/*.scss'],
tasks: ['compass']
},
templates: {
files: ['templates/*.jade'],
tasks: ['jade']
}
},
You can see that I only want livereload to fire when there have been changes to my compiled css (*.css) or to my compiled html. If I edit a SCSS file, I want to fire off just compass. If I edit a jade template, I want to only fire the jade to HTML compiler. I think you can see what's going on. You can toy with this, just be smart about it because you could get caught in an infinite loop.
Lastly, you need to fire off these processes. I like tying them all to my main grunt task because my gruntfile is just that sweet.
// Default task.
grunt.registerTask('default', ['livereload-start', 'connect', 'regarde']);
Now, when you fire up grunt in the CLI, you should (hopefully, maybe, cross your fingers) get something like this:
Running "connect:livereload" (connect) task
Starting connect web server on localhost:9999.
Browse to http://localhost:9999/yourpage.html and watch magic happen.
full gruntfile here. full package.json here.
Here is a solution based on Gulp instead of Grunt and the following Gulpfile.js to get livereload working:
var gulp = require('gulp');
var connect = require('connect');
var connectLivereload = require('connect-livereload');
var opn = require('opn');
var gulpLivereload = require('gulp-livereload');
var config = {
rootDir: __dirname,
servingPort: 8080,
// the files you want to watch for changes for live reload
filesToWatch: ['*.{html,css,js}', '!Gulpfile.js']
}
// The default task - called when you run `gulp` from CLI
gulp.task('default', ['watch', 'serve']);
gulp.task('watch', ['connect'], function () {
gulpLivereload.listen();
gulp.watch(config.filesToWatch, function(file) {
gulp.src(file.path)
.pipe(gulpLivereload());
});
});
gulp.task('serve', ['connect'], function () {
return opn('http://localhost:' + config.servingPort);
});
gulp.task('connect', function(){
return connect()
.use(connectLivereload())
.use(connect.static(config.rootDir))
.listen(config.servingPort);
});
I know this is a little old but can help someone.
In the Gruntfile.js add "options":
sass: {
files: 'scss/**/*.scss',
tasks: ['sass'],
options: {
livereload: true,
}
}
In the index add:
<script src="http://localhost:35729/livereload.js"></script>

Resources