At the beginning of my JavaScript file I have a comment that host the project details like this:
// { project name }
// { project website }
// { author }
For instance it should look like this
/// FoobarProject 2.0.1
/// www.foobar.com/foobarproject
/// John Doe <john.doe#hotmail.com>
;(function(){
//...
}());
What is the best way to align these details with my package.json? So when I update the version in the package.json and execute my "build" task, gulp should update the version.
I do not like the idea to have two file:
File "A" that uses placeholders (e.g. {{ version }})
File "B" that is the outcome of the build process where placeholders are populated with the values.
I prefer the approach that the build-task replaces the values in my file directly. Furthermore after the minifier (uglify) is executed this comment should be prefixed.
So my question boils down to: What is the best approach to implement "replaceFirstThreeLinesWith":
gulp.task('inject-projectdetails', function(){
var header = [
util.format('// FoobarModule.js %s', pkg.version),
util.format('// %s', pkg.homepage),
util.format('// %s', pkg.author),
].join('');
return gulp.src('FoobarModule.js')
.pipe( replaceFirstThreeLinesWith(header) )
.pipe(gulp.dest('.') );
});
You can use gulp-header plugin: https://www.npmjs.com/package/gulp-header
Related
I'm writing a shell script, and would like to use template it, by keeping my variables in a json file.
I'm a beginner to javascript, and so can't seem to get the hang of how to use nunjucks to render my templates. Can you please help me get this simple example to work?
Here's my current attempt. (I have npm installed)
In my project directory :
$ npm install nunjucks
I create sample.njk with the following contents :
{{ data }}
And index.js with the following content :
var nunjucks = require('nunjucks')
nunjucks.configure({ autoescape: true });
nunjucks.render('sample.njk', { data: 'James' });
My project directory then, looks like :
index.js node_modules/ sample.njk
I run index.js with node as
$ node index.js
How do I get it to output (to the command line, or to a new file):
James
after processing the template?
I've tried looking at gulp-nunjucks and gulp-nujucks-render, but there's too much going on there, and I can't even get a simple task accomplished here.
When I define my data in a json file, I only need pass it as a context in the nunjucks.render() function, right?
Thanks for your help.
Depends on what you're trying to accomplish with the data outputted by the Nunj render. If you simply want to print it to the terminal, a simple console.log(); will work.
In Express, res.render takes an optional third param which is a fn. You would do it as such:
var nunjucks = require('nunjucks');
nunjucks.configure({ autoescape: true });
nunjucks.render('sample.njk', { data: 'James' }, function (err, output) {
// If there's an error during rendering, early return w/o further processing
if (err) {
return;
}
// The render fn calls the passed-in fn with output as a string
// You can do whatever you'd like with that string here
console.log(output);
});
I'm developing my own generator with Yeoman. When I try to copy some files, nothing happens. No error, the process continues until it reach the end, but no files are copied. The generator has a /templates dir with a bunch of html files, each file has a few html lines, at the moment quite simple stuff.
This is my copy method:
copyMainFiles: function(){
console.log('copyMainFiles dir:' + process.cwd() + '+++++');
console.log('file exists? '+fs.existsSync('_footer.html') );
this.copy("_footer.html", "app/footer.html");
console.log('footer copied');
this.copy("_gruntfile.js", "Gruntfile.js");
console.log('gruntfile copied');
this.copy("_package.json", "package.json");
console.log('package copied');
this.copy("_main.css", "app/css/main.css");
console.log('main.css copied');
var context = {
site_name: this.appName
};
console.log('all files copied');
//template method makes the replacement and then copy
this.template("_header.html", "app/header.html", context);
console.log('header template processed');
},
this is the console output:
$ yo trx
method 1 just ran
method 2 just ran
? What is your app's name ?
Kosheen
? Would you like to generate a demo section ? Yes
all dirs created
copyMainFiles dir:C:\cygwin\Applications\MAMP\htdocs\prueba-trx+++++
file exists? false
footer copied
gruntfile copied
package copied
main.css copied
all files copied
header template processed
running npm
and that's it. Never returns to system prompt.
Besides the fact that fs.existsSync returns false (the file exists: htdocs\generator-trx\generators\app\templates_footer.html ), if I try to copy a non-existent file I get the typical error.
Folders are created previously with no issue. There's a .yo_rc.json file with {} in the root of the destination folder. The Yeoman version is 1.4.8, working on Windows 7.
Is copy() the proper way to do this or is no longer valid? How can I copy a simple file in this scenario?
Beside the fact of I was using deprecated methods, the proper way to achive this task is as follow:
this.fs.copy(
this.templatePath('_bower.json'),
this.destinationPath('bower.json')
);
Not sure what your issue is, but you should read the Yeoman official documentation on how to handle files: http://yeoman.io/authoring/file-system.html
You're using old and deprecated methods.
Wot I got
I have a gulpfile that produces app.min.js and libs.min.js; fairly selfexplanatory:
var dev = {
libs: [
'bower_components/angular/angular.min.js',
'bower_components/angular-foundation/mm-foundation-tpls.min.js',
'bower_components/underscore.string/dist/underscore.string.min.js'
]
};
var build = {
js: 'public/js'
};
gulp.task('libs', function() {
return gulp.src(dev.libs)
.pipe(concat('libs.min.js'))
.pipe(uglify({mangle: false}))
.pipe(gulp.dest(build.js));
});
In this setup, whenever I add or remove a library, I have to manually add it to the dev.libs array (and in the right order, too), then restart Gulp to see the new lib file.
Wot I WANT
I want to be able to concat the js libs I use without having to specifically define them in (array) dev.libs. At the moment if I use return gulp.src('**/*.js'), I believe it will concat every single js file in bower_components, which'd obviously be ridiculous.
Question
Is there a way to automatically load and concat the libraries I need, without having to define them in a gulpfile?
For Bower, you can use the plugin main-bower-files that will parse the content of your bower.json and search for the main file(s) of each of your dependency, so you don't have to declare each lib.
var bowerFiles = require('main-bower-files');
You can then do :
gulp.task('libs', function () {
return gulp.src(bowerFiles())
.pipe(concat('libs.min.js'))
.pipe(uglify({mangle: false}))
.pipe(gulp.dest(build.js));
});
This is currently possible:
ember build --environment=production
... and I would like to do something like this instead:
ember build --environment=production --baseurl=foo
but config/environment.js only gets passed in the value of environment.
Is it possible to get the value of the other options passed in at the command line too?
You could set environment variables the old fashioned way (export WHATEVER=wee) from terminal or as part of a build script, then reference them in your Brocfile.js via node with process.env.WHATEVER. After that, it would be a matter of having broccoli do whatever it is you needed to do with them. You could pre-process files and replace strings, for example.
... just a suggestion. Not sure if that's what you're looking for or not.
It appears that this is not allowed:
Looking in node_modules/ember-cli/lib/commands/build.js, we see:
availableOptions: [
{ name: 'environment', type: String, default: 'development' },
{ name: 'output-path', type: path, default: 'dist/' }
],
... and in node_modules/ember-cli/lib/models/command.js
this.availableOptions.forEach(function(option) {
knownOpts[option.name] = option.type;
});
... which together mean that any options that are not defined, for each subcommand of ember, get discarded.
You can do foo=bar ember build (however doing ember build foo=bar doesn't work)
And the argument is available via process.env.foo.
To extend upon #ben's answer.
The raw command line arguments are available inside ember-cli-build.js and other files from the
process.argv.[]
So a command like this
ember build staging
you can access via:
process.argv.includes('staging')
see node's documentation for whats available.
https://nodejs.org/docs/latest/api/process.html
Is it possible to "require" an entire folder using requireJS.
For example, I have a behaviors folder with a ton of behavior js files. I'd really like to be able to simply use require(['behaviors/*'], function() {...}); to load everything in that folder rather than having to keep that list up to date. Once compressed and optimized I'd have all those files lump together, but for development it's easier to work with them individually.
javascript in browser has no filesystem access and so it can't scan a directory for files. If you are building your app in a scripting language like php or ruby you could write a script that scans the directory and adds the file names to the require() call.
I don't know if I can recommend this approach anymore. I think the more explicit way to do this is by manually "requiring"/"exporting" the functionality you need. The exception I think is if you have a "namespace" of files that you want exported see below "Babel and ES6 Module Import Declarations (export-namespace-from) or see below "Babel and ES6 Module Import Declarations.
These solutions also assume that you have a meaningful file structure - where file names become part of that "require" * definition.
However, if you still need to do this there are a few existing tools and methods that might provide the behavior that you're looking for.
Possible Solutions
Babel and ES6 Module Import Declarations (plugin-export-namespace-from)
Have a setup that is ES6 compliant.
You need to update your .babelrc file to include babel-plugin-proposal-export-namespace-from.
Use export namespace plugin by writing syntax like the following:
common/index.js
export * from './common/a'; // export const a = false;
export * from './common/b'; // export const b = true;
main.js
import { a, b } from './common';
console.log(a); // false
console.log(b); // true
Babel and ES6 Module Import Declarations (plugin-wildcard)
Have a setup that is ES6 compliant.
You need to update your .babelrc file to include babel-plugin-wildcard.
Use wildcard namespace plugin by writing syntax like the following:
main.js
import { a, b } from './common/*'; // imports './common/a.js' and './common/b.js'
console.log(a); // false
console.log(b); // true
RequireJS (Now Outdated)
Download and install require-wild npm install require-wild
Configure the declaration as follows
grunt.initConfig({
requireWild: {
app: {
// Input files to look for wildcards (require|define)
src: ["./**/*.js"],
// Output file contains generated namespace modules
dest: "./namespaces.js",
// Load your require config file used to find baseUrl - optional
options: { requireConfigFile: "./main.js" }
}
}
});
grunt.loadNpmTasks("require-wild");
grunt.registerTask('default', ['requireWild']);
Then run the grunt task. Your file will be generated. Modify your setup to load namespaces.js
require(['namespaces'], function () { ... });
This now allows modules under src to use dependencies glob pattern matching.
require(['behaviors/**/*'], function (behaviors) { }
I know this is old, but I'd like to share my solution:
For this solution you need JQuery
1) Create a bash script that will list all the js files in
"MyDirectory/", and save it to "directoryContents.txt":
#!/bin/bash
#Find all the files in that directory...
for file in $( find MyDirectory/ -type f -name "*.js" )
do
fileClean=${file%.js} #Must remove .js from the end!
echo -n "$fileClean " >> MyDirectory/directoryContents.txt
done
File will look like this:
MyDirectory/FirstJavascriptFile MyDirectory/SecondJavascriptFile
MyDirectory/ThirdJavascriptFile
Problem with my script! Puts an extra " " at the end, that messes things up! Make sure to remove the excess space at the end of directoryContents.txt
2) Then in your Client side JS code:
do a "GET" request to retrieve the text file
For each entry (split by the space), 'require' that file:
.
$.get( "MyDirectory/directoryContents.txt", {}, function( data ) {
var allJsFilesInFolder = data.split(" ");
for(var a=0; a<allJsFilesInFolder.length; a++)
{
require([allJsFilesInFolder[a]], function(jsConfig)
{
//Done loading this one file
});
}
}, "text");
I was having a problem with this code not finishing before my other code, so Here's my extended answer:
define([''], function() {
return {
createTestMenu: function()
{
this.loadAllJSFiles(function(){
//Here ALL those files you need are loaded!
});
},
loadAllJSFiles: function(callback)
{
$.get( "MyDirectory/directoryContents.txt", {}, function( data ) {
var allJsFilesInFolder = data.split(" ");
var currentFileNum = 0;
for(var a=0; a<allJsFilesInFolder.length; a++)
{
require([allJsFilesInFolder[a]], function(jsConfig)
{
currentFileNum++;
//If it's the last file that needs to be loaded, run the callback.
if (currentFileNum==allJsFilesInFolder.length)
{
console.log("Done loading all configuration files.");
if (typeof callback != "undefined"){callback();}
}
});
}
}, "text");
}
}
});
What I ended up doing was everytime my Node server boots, it will run the bash script, populating directoryContents.txt. Then My client side just reads directoryContents.txt for the list of files, and requires each in that list.
Hope this helps!
There isn't really a way to do this conceptually on the fly (that I know of).
There's a few work arounds though:
Use grunt and concat and then just require that behemoth...I know, kinda sucky.
What I think is a better solution... use a require hierarchy like so:
require('/js/controllers/init', function(ctrls){
ctrls(app, globals);
});
// /js/controllers/init.js
define('js/controllers/index', 'js/controllers/posts', function(index, posts){
return function protagonist(app, globals){
var indexModule = index(app, globals);
var indexModule = posts(app, globals);
return app || someModule;
};
});
// /js/controllers/index.js
define('js/controllers/index', 'js/controllers/posts', function(index, posts){
return function protagonist(app, globals){
function method1(){}
function method2(){}
return {
m1: method1,
m2: method2
};
};
});
Note that "protagonist" function. That allows you to initialize modules before their use, so now you can pass in a 'sandbox' -- in this case app and globals.
Realistically, you wouldn't have /js/controllers/index.js... It should probably be something like /js/controllers/index/main.js or /js/controllers/index/init.js so that there is a directory adjacent to (sibling of) /js/controllers/init.js called "index". This will make your modules scalable to a given interface -- you can simply swap modules out and keep your interface the same.
Hope this helps! Happy coding!
I wrote a library to solve this problem. Eventually someone else came along and improved my library, here it is:
https://github.com/smartprocure/directory-metagen
You can use my lib with Gulp or whatever - it generates metadata for your project and RequireJS can use that metadata to require the desired files from the filesystem.
Using this lib will produce a RequireJS module that looks something like this:
define(
[
"text!app/templates/dashboardTemplate.ejs",
"text!app/templates/fluxCartTemplate.ejs",
"text!app/templates/footerTemplate.ejs",
"text!app/templates/getAllTemplate.ejs",
"text!app/templates/headerTemplate.ejs",
"text!app/templates/homeTemplate.ejs",
"text!app/templates/indexTemplate.ejs",
"text!app/templates/jobsTemplate.ejs",
"text!app/templates/loginTemplate.ejs",
"text!app/templates/overviewTemplate.ejs",
"text!app/templates/pictureTemplate.ejs",
"text!app/templates/portalTemplate.ejs",
"text!app/templates/registeredUsersTemplate.ejs",
"text!app/templates/userProfileTemplate.ejs"
],
function(){
return {
"templates/dashboardTemplate.ejs": arguments[0],
"templates/fluxCartTemplate.ejs": arguments[1],
"templates/footerTemplate.ejs": arguments[2],
"templates/getAllTemplate.ejs": arguments[3],
"templates/headerTemplate.ejs": arguments[4],
"templates/homeTemplate.ejs": arguments[5],
"templates/indexTemplate.ejs": arguments[6],
"templates/jobsTemplate.ejs": arguments[7],
"templates/loginTemplate.ejs": arguments[8],
"templates/overviewTemplate.ejs": arguments[9],
"templates/pictureTemplate.ejs": arguments[10],
"templates/portalTemplate.ejs": arguments[11],
"templates/registeredUsersTemplate.ejs": arguments[12],
"templates/userProfileTemplate.ejs": arguments[13]
}
});
You can then require modules in your front-end like so:
var footerView = require("app/js/jsx/standardViews/footerView");
however, as you can see this is too verbose, so the magic way is like so:
name the dependency above as allViews!
now you can do:
var allViews = require('allViews');
var footerView = allViews['standardViews/footerView'];
There are two advantages to requiring directories whole:
(1) in production, with the r.js optimizer, you can point to one dependency (module A) and it can then easily trace all of A's dependencies that represent a entire directory
(2) in development, you can require whole directories up front and then use synchronous syntax to require dependencies because you know they have already been loaded
enjoy "RequireJS-Metagen"
https://github.com/smartprocure/directory-metagen
https://www.npmjs.com/package/requirejs-metagen
https://github.com/ORESoftware/requirejs-metagen