Use node `fs` module on webpack compile - node.js

A bit about what I'm trying to achieve.
I'm building dev library that shows the list of files. And I want to set file color depending on when file was changed.
So, as a result of generation, I want an array like this:
[
{
lastChange: '2009-06-29T11:11:55Z',
fileContents: {name: 'VmSome'},
},
// ...
]
This is meant to work in browser environment. Meaning all file related information should be included into bundle.
Current progress
At the moment I'm not quite sure whether that's even possible.
I'm getting a list of files via webpack require.context:
require.context('./tree', true, /.js$/)
This gives me access to file content and path. But not to anything else.
Thanks for your attention.

I would first try modifying webpack-file-list-plugin. As of now, it creates a JSON that gives all files packed, their name and some more info... You could definitely add your code to fetch more information to the JSON.
https://github.com/object88/webpack-file-list-plugin/blob/master/src/index.js

Related

Chrome extension, Grunt+Bower (from yeoman template) won't load plugins

I just though I make my life easier by sticking to common structures, so I started transferring a chrome browser extension to a yeoman template format
(https://github.com/yeoman/generator-chrome-extension).
Unfortunately it simply does not work when I try to just add my first basic bower source that I need:
https://github.com/Yaffle/EventSource
Here is what I did:
Set up the new extension with the yeoman helper
$ bower install EventSource --save
Added event source to the manifest like so
"background": {
"scripts": [
"scripts/chromereload.js",
"app/bower_components/EventSource/eventsource.js",
...
Add "new EventSource('http://localhost:9292/updates');" to background.js
Other than that the project is untouched.
And whenever I start the project with grunt it fails not finding EventSource like so "'EventSource' is not defined."
Adding the eventsource.js directly to my script folder and require it from there fails even worse by linting the eventsource.js file (that works perfectly fine) and aborting it for too many warnings (like using single quotes).
Previously this whole project worked pretty fine without grunt/bower and now it won't even start after I added the first real line of code. This is quite disappointing for a tool that is supposed to make your life so much easier.
Does it fail because of the warnings in the eventsource.js? In the first case (via bower) it does not say anything about this so I'm not sure.
I could go on trying out different combinations but I'm obviously missing a core concept or something like this here.
Any idea?
Update:
After some more trying and giving up i found the magic "grunt bowerInstall" command, to add the script-tags in the template automatically - still no help.
I did also try again on a fresh project with just jQuery (assuming this has to work..), well it still does not.
Neither in the popup.js (where the html template includes jQuery) nor in the background script (where the manifest includes it).
I probably read every manual/how-to on hot to use either of those components and still get nowhere.
Another day another try:
Starting with a clean mind i looked a bit more into it today finding out that apparently you have to "whitelist" globals like $ in jshint like so:
http://jshint.com/docs/options/#jquery
Still not sure if this is actually the best approach as it seems very counter-intuitive with promised ease of getting started of the yeoman/grunt/bower framework.
EventSource is probably a global variable. You can try declaring it as false in the .jshintrc file to prevent it from being overwritten.
"globals" : {
"chrome": true,
"crypto": true,
"EventSource": false
}
See if that works.
Read more about .jshintrc + global variables at: JSHint and jQuery: '$' is not defined

Add a Timestamp to the End of Filenames with Grunt

During my Grunt tasks, add a unique string to the end of my filenames. I have tried grunt-contrib-copy and grunt-filerev. Neither have been able to do what I need them to...
Currently my LESS files are automatically compiled on 'save' in Sublime Text 3 (so this does not yet occur in my grunt tasks). Then, I open my terminal and run 'grunt', which concatenates (combines) my JS files. After this is done, then grunt should rename 'dist/css/main.css' and 'dist/js/main.js' with a "version" at the end of the filename.
I have tried:
grunt-contrib-copy ('clean:expired' deletes the concatenated JS before grunt-contrib-copy' can rename the file)
grunt-filerev ('This only worked on the CSS files for some reason, and it inserted the version number BEFORE the '.css'. Not sure why it didn't work on the JS files.')
Here's my Gruntfile.js
So, to be clear, I am not asking for "code review" I simply need to know how I can incorporate a "rename" process so that when the tasks are complete, I will have 'dist/css/main.css12345 & dist/js/main.js12345' with no 'dist/css/main.css' or 'dist/js/main.js' left in their respective directories.
Thanks in advance for any help!
UPDATE: After experimenting with this, I ended up using grunt-contrib-rename and it works great! I beleieve the same results can be achieved via grunt-contrib-copy, in fact I know it does the same thing. So either will work. As far as support for regex, not sure if both support it, so may be something else worth looking into before choosing one of these plugins :)
Your rename:dist looks like it should do what you want, you just need to move clean:dist to be the first task that runs (so it deletes things from the prior build rather than the current build). The order of tasks is defined by the array on this last line:
grunt.registerTask('default', ['jshint:dev', 'concat:dist', 'less:dist', 'csslint:dist', 'uglify:dist', 'cssmin:dist', 'clean:dist', 'rename:dist']);
That said, I'm not sure why you want this behavior. The more common thing to do is to insert a hash of the file into the filename before the file extension.
The difference between a hash and a timestamp is that the hash value will always be the same so long as the file contents don't change - so if you only change one file, the compiled output for just that file will be different and thus browsers only need to re-downloaded that one file while using cached versions of every other file.
The difference between putting this number before the file extension and after the extension is that a lot of tools (like your IDE) have behavior that changes based on the extension.
For this more standard goal, there are tons of ways to accomplish it but one of the more common is to combine grunt-filerev with grunt-usemin which will create properly named files and also update your HTML file(s) to reference these new file names
I'm not sure to understand completely what end you want, but if you add a var timestamp = new Date().getTime(); at the beginning of your gruntfile and concatenate to your dest param that should do the job.
dest: 'dist/js/main.min.js' + timestamp
Is it what your looking for?

Grunt-Includes Templating On Filename?

My current Grunt implementation uses grunt-includes to wrap all of my pages in the header/footer code. What I am looking for is a way to add dynamic bits to the header and footer to load CSS/JS as well as add classes to the body tag, but I need them to be based on the name of the file requesting the include during the grunt-includes task.
I could get everything done I needed to if I could simply get grunt-includes to pass the name of the requesting file into the included file. In reading the documentation for grunt-includes I can see that there appears to be some kind of template for {{fileName}} and {{file}} but I can't seem to get these to work.
Just to clarify, what I am looking for is, when running grunt-includes via grunt, if a file named myFile.html has the line include "global/myHeader.html", myFile or myFile.html gets passed into global/myHeader.html as it is concatenated onto myFile.html.
Can somebody please point me in the right direction here? I've been spinning my wheels for two days.
My includes function that I am currently using is as follows:
includes: {
files: {
src: ['sources/*.html'], // Source files
dest: 'app', // Destination directory
flatten: true,
cwd: '.',
options: {
silent: true,
}
}
},
The template setting goes in the options object of the files object. This is the only place where {{file}} and {{fileName}} can be used. This means if you wan't to "pass" these into the requested files you either have to put the entire string in the template (not recommended), or pass just the file name into a hidden tag and use JavaScript to handle whatever dynamics you needed.
I recommend using grunt template for this instead:
http://gruntjs.com/api/grunt.template

Order of resolution with nodejs require module

Suppose I have all of foo.js, foo.coffee, and foo.jsonin the same directory, and I say require './foo' from another (coffeescript) file in that location, what rule governs which one will be loaded?
A short experiment (using require.resolve './foo') would seem to indicate that the javascript file wins over the other two.
Indeed, looking at require.extensions it looks like .js being mentioned there as the first item—but then, object attribute names are inherently unordered in javascript, right?, so any name added to that property could potentially re-order the entries—could that lead to another resolution order?
Just wondering, as i couldn't find any documentation. it does become relevant when you do (and maybe you shouldn't) coffee --compile route/to/directory.
.js is loaded first (this also means that it's better to use full name.json for your fixture instead of name as it could be shadowed by name.js)
From "modules" documentation:
If the exact filename is not found, then node will attempt to load the required filename with the added extension of .js, .json, and then .node.
Also, read name resolution algorithm in pseudo-code:
LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If X.js is a file, load X.js as JavaScript text. STOP
3. If X.node is a file, load X.node as binary addon. STOP
After (1,2,3) extensions set in require.extensions are checked in the order they a set (for CoffeScript, require("coffe-script") installs .coffee handler).
The behavior in V8 is to iterate over named properties in the order they were originally assigned, so I would expect .js to always be first.
This post references that behavior

require.js - runtime dynamic variables to build path

Is it possible to inject runtime information in to a require.js "data main" script and use to build paths? More explanation...
In my node.js app.js I dynamically find the path to the configured 'theme' like this:
var themePath = require('./conf/config.js').config.theme.full_path;
and later in the require.js data main script, I'd like to prepend this theme path when defining paths. So assuming I've set my requirejs data-main="xxx" and the following is the xxx file, I'd like to do something like the following:
require.config({
baseUrl: "/js/",
paths: {
"templates" : DYNAMIC_THEME_PATH + '/templates',
"views" : DYNAMIC_THEME_PATH + '/views'
}
});
I'm not sure 1. how I can "see" the themePath from within this require.js data main file, and 2. is this even possible?
EDIT - My solution
So the real challenge I was having was getting a runtime variable discovered on the server in to the require.js data main script. In node land, global doesn't correspond to the window on the client side (of course) because the javascript isn't in to the browser yet .. duh. So I don't see how you can get this discoverable in the client side script.
Ok, so what I WAS able to do was inject the discovered theme path in the ejs, then, dynamically load the data main script with that prepended like:
<script data-main="<%= theme_path %>/main" src="../js/libs/require-jquery.js"></script>
Of course this means I have to have the data main script in the theme directory which wasn't my initial plan; however, it does have the advantage that I can then use relative paths to load my path/to/templates path/to/views, etc. etc.
Lastly, I sort of hate when folks answer they're own questions .. so I'm going to leave this up in hopes that someone can either give me a better recommendation or better explain this and they can get the credit ;)

Resources