How to make the Jade template compress inline javascript automatically? - node.js

when I check the html page source, the HTML tags and text content are compressed without blank and line, but inline javascript.

Just discovered something that works for me in Jade v0.30.0:
Rename your .js file with a .uglify extension
In your Jade template, use:
include name-of-javascript-file.uglify
Why it works: Digging into the Jade source code, I discovered a file called filters.js. In there, you'll see a dependency on transformers. In lib/transformers.js (of the transformers module), you will see the various transform utilities, including uglify. Apparently, Jade will call on any of those transformers if you match the right file extension in your include declaration.

I'm not sure about it and haven't tested it yet, but you can probalby add a filter and utilize UglifyJS. For example
var uglyParser = require("uglify-js").parser;
var uglyUgly = require("uglify-js").uglify;
var uglify = function(str) {
var ast = uglyParser.parse(str);
ast = uglyUgly.ast_mangle(ast);
ast = uglyUgly.ast_squeeze(ast);
return uglyUgly.gen_code(ast);
}
To be honest, I'm not sure where to put that in jade so it's treated as a filter. For now you should be able to just stick it at https://github.com/visionmedia/jade/blob/master/lib/filters.js.
The usage in jade would then be:
script(type="text/javascript")
:uglify
<Your JavaScript Code>
Again I haven't tested it. But I think it should work. I'll test it later today.

According to the docs, you can use any JSTransformer as a jade filter. So, where you would normally do this to inline JS:
script.
(function doSomething () { … })();
you should do it like this:
script
:uglify-js
(function doSomething () { … })();

Related

not able to load jquery via require [duplicate]

I'm getting this error when I browse my webapp for the first time (usually in a browser with disabled cache).
Error: Mismatched anonymous define() module: function (require) {
HTML:
<html>
.
.
.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script> var require = { urlArgs: "v=0.4.1.32" }; </script>
<script data-main="assets/js/main" src="assets/js/libs/require.js"></script>
<script src="assets/js/ace/ace.js?v=0.4.1.32"></script>
</body>
</html>
JS:
$(function () {
define(function (require) {
// do something
});
});
Anyone know exactly what this error means and why its happening?
source file, a short discussion about it in the github issues page
Like AlienWebguy said, per the docs, require.js can blow up if
You have an anonymous define ("modules that call define() with no string ID") in its own script tag (I assume actually they mean anywhere in global scope)
You have modules that have conflicting names
You use loader plugins or anonymous modules but don't use require.js's optimizer to bundle them
I had this problem while including bundles built with browserify alongside require.js modules. The solution was to either:
A. load the non-require.js standalone bundles in script tags before require.js is loaded, or
B. load them using require.js (instead of a script tag)
In getting started with require.js I ran into the issue and as a beginner the docs may as well been written in greek.
The issue I ran into was that most of the beginner examples use "anonymous defines" when you should be using a "string id".
anonymous defines
define(function() {
return { helloWorld: function() { console.log('hello world!') } };
})
define(function() {
return { helloWorld2: function() { console.log('hello world again!') } };
})
define with string id
define('moduleOne',function() {
return { helloWorld: function() { console.log('hello world!') } };
})
define('moduleTwo', function() {
return { helloWorld2: function() { console.log('hello world again!') } };
})
When you use define with a string id then you will avoid this error when you try to use the modules like so:
require([ "moduleOne", "moduleTwo" ], function(moduleOne, moduleTwo) {
moduleOne.helloWorld();
moduleTwo.helloWorld2();
});
I had this error because I included the requirejs file along with other librairies included directly in a script tag. Those librairies (like lodash) used a define function that was conflicting with require's define. The requirejs file was loading asynchronously so I suspect that the require's define was defined after the other libraries define, hence the conflict.
To get rid of the error, include all your other js files by using requirejs.
Per the docs:
If you manually code a script tag in HTML to load a script with an
anonymous define() call, this error can occur.
Also seen if you
manually code a script tag in HTML to load a script that has a few
named modules, but then try to load an anonymous module that ends up
having the same name as one of the named modules in the script loaded
by the manually coded script tag.
Finally, if you use the loader
plugins or anonymous modules (modules that call define() with no
string ID) but do not use the RequireJS optimizer to combine files
together, this error can occur. The optimizer knows how to name
anonymous modules correctly so that they can be combined with other
modules in an optimized file.
To avoid the error:
Be sure to load all scripts that call define() via the RequireJS API.
Do not manually code script tags in HTML to load scripts that have
define() calls in them.
If you manually code an HTML script tag, be
sure it only includes named modules, and that an anonymous module that
will have the same name as one of the modules in that file is not
loaded.
If the problem is the use of loader plugins or anonymous
modules but the RequireJS optimizer is not used for file bundling, use
the RequireJS optimizer.
The existing answers explain the problem well but if including your script files using or before requireJS is not an easy option due to legacy code a slightly hacky workaround is to remove require from the window scope before your script tag and then reinstate it afterwords. In our project this is wrapped behind a server-side function call but effectively the browser sees the following:
<script>
window.__define = window.define;
window.__require = window.require;
window.define = undefined;
window.require = undefined;
</script>
<script src="your-script-file.js"></script>
<script>
window.define = window.__define;
window.require = window.__require;
window.__define = undefined;
window.__require = undefined;
</script>
Not the neatest but seems to work and has saved a lot of refractoring.
Be aware that some browser extensions can add code to the pages.
In my case I had an "Emmet in all textareas" plugin that messed up with my requireJs.
Make sure that no extra code is beign added to your document by inspecting it in the browser.
Or you can use this approach.
Add require.js in your code base
then load your script through that code
<script data-main="js/app.js" src="js/require.js"></script>
What it will do it will load your script after loading require.js.
I was also seeing the same error on browser console for a project based out of require.js. As stated under MISMATCHED ANONYMOUS DEFINE() MODULES at https://requirejs.org/docs/errors.html, this error has multiple causes, the interesting one in my case being: If the problem is the use of loader plugins or anonymous modules but the RequireJS optimizer is not used for file bundling, use the RequireJS optimizer. As it turns out, Google Closure compiler was getting used to merge/minify the Javascript code during build. Solution was to remove the Google closure compiler, and instead use require.js's optimizer (r.js) to merge the js files.

Passing variable from jade to ng-init not working

I'm trying to pass an object from jade to ng-init in angular
This: doesn't work:
ng-init='tables=!{JSON.stringify(tables)}'
This: expands but,
ng-init='tables=#{JSON.stringify(tables)}'
the output is unescaped and filled with "s
ng-init="tables={"12":{"id":....
and the view isn't updated in either of the cases. This article implies that first one should work, but like I said, it doesn't even expand,
ng-init='tables=!{JSON.stringify(tables)}'
in source code shows up exactly the same in the HTML source
ng-init='tables=!{JSON.stringify(tables)}'
Actually, the #{...} approach seems to work fine.
It is probably the way console.log prints attributes' values that confused you.
ng-init="tables=#{JSON.stringify(tables)}"
Take a look at this short demo.
In what use-case you want to pass data directly from Jade to angular? I think you could to this job in controller like this :
$scope.init = function () {
// init stuff
}
...and in your view :
ng-init = init()

Require a javascript library inside Jade

How do I require a library so that it works inside Jade.
Like if I want to be able to use CircularJSON in Jade
script var object = #{CircularJSON.stringify(object)}
I would basically need to define the function from that library into Jade
- var CircularJSON = function(e,t){function l(e,t,o){var u=[],...//whole function
which would be impractical and possibly impossible for much more complex libraries.
Is there a way to somehow simply require it instead?
var myLib = require('../mylib');
response.render("index.jade", {
lib : myLib
});
index.jade now has the myLib object. Now just use as you would anywhere else.
Just require it in node and pass it to the template in the locals. locals can include functions as well entire modules, objects and scalar data.
I like to take an approach similar to Peter Lyons and Zhifeng Hu (in another post), but instead of requiring everything into locals, I just require "require", then I can pull things in as needed in my templates.
app.use((req, res, next) => { res.locals.require = require; next() })
and then in Jade/Pug
- const moment = require('moment')
div Created at: #{moment(data.createdAt).fromNow()}
Basically the same thing, but I can keep the require code in the template where it's used.

How to namespace modules in the browser but not in node

I have seen many examples of the self-invoking pattern that detects the global object (module.export / window) -- but I am not sure how to do namespacing with this pattern and still have it work in node the same way.
(function(exports) {
'use strict';
// how do i do something like this and have it work in node as well
// exports Namespace.Models.HelloWorld = function () {}
exports.say = function() {
return 'hello world';
};
}(typeof exports === 'undefined' ? this.helloworld = {} : exports));
After looking at the code some more I think you're code should work fine. What you want is to namespace all your code so that it doesn't pollute the global namespace right? So what you need is a single object in the global namespace that you then put all your code under.
Note: The global namespace in the browser is window in case you didn't know.
For example, JQuery creates only two global objects: jQuery and $. Everything you do with JQuery involves only those two global objects. JQuery even has a compatibility mode that disables the dollar sign so then you only have the jQuery object. The pattern people use to get the dollar sign back even when it's been disabled is to do this:
(function ($) {
// Do stuff with $
})(jQuery);
It's a self-invoking function that passes the jQuery object into itself which then becomes the $ argument. That way you can still have the convenience of the dollar sign without clogging up the global window object with yet another property. In your code (this.helloWorld) the this keyword refers to the global namespace (unless your code is wrapped inside another function or something and you didn't post it). What you've done is create a property on the window object (global namespace) called helloWorld, you set it to an empty object, and you pass it in. But you only do this if exports is undefined. That's the part that identifies if you're in node or not. exports will only be undefined if you're in the browser because exports is only available in node modules (just don't add an exports property to the global namespace in the browser, lol).
Note: Node has no application-wide "global" namespace that things get put into by default. Everything in node is scoped to the module level. So even if you define a variable on the first line of your module you can still define the exact same variable on the first line of another module and they won't conflict with each other. There is however, a global object in node that truly is global and you can access its properties from any module. I do not encourage you to use the global object, like, ever. If you need to use that object then you should probably reconsider your application structure.
Whatever you attach to exports in node becomes available to any other module that requires it.
// helloWorld.js
exports.message = "Hello, world!";
and then...
// main.js
var helloWorld = require('./helloWorld.js');
// Now all the properties are available on the variable `helloWorld`.
console.log(helloWorld.message);
// Prints "Hello, world!" to the console.
In the browser you want to do something similar by attaching a single uniquely named object to window and then whomever uses your script should access all your functions through that "namespace". So finally we have this:
// helloWorld.js
(function (myNamespace) {
myNamespace.message = "Hello, world!";
})(typeof exports === 'undefined' ? this.helloWorld = {} : exports)
If exports does not exist then add helloWorld to this (which refers to window when in the global scope like it is in this example) and pass that in. If exports does exist then pass it in instead. Now inside the function we can attach properties and methods to myNamespace and they'll either be attached to window.helloWorld or exports depending on the environment.
I could add the above helloWorld.js file to my node application and use it like this:
// nodeScript.js
var helloWorld = require('./helloWorld.js');
console.log(helloWorld.message);
Or I could add the above helloWorld.js file to my web app. Your page might look like this:
// index.html
<html>
<head>
<title>My Site</title>
<script src="helloWorld.js" />
<script src="clientScript.js" />
</head>
<body>
<div id="messageBox"></div>
</body>
</html>
And your script might look like this:
// clientScript.js
document.getElementById('messageBox').innerHTML = helloWorld.message;
The above page would end up with "Hello, world!" inside the div because it read the message from our module's exposed properties :)
Hopefully that clears things up. Sorry for jumping in with browserify at first instead of directly answering your original question. I do highly recommend browserify though :)
You need browserify. Write your modules in the node-style and then let browserify turn them into proper client-side scripts :)
From browserify home page:
Write your browser code with node.js-style requires:
// main.js
var foo = require('./foo');
var gamma = require('gamma');
var n = gamma(foo(5) * 3);
var txt = document.createTextNode(n);
document.body.appendChild(txt);
Export functionality by assigning onto module.exports or exports:
// foo.js
module.exports = function (n) { return n * 11 }
Install modules with npm:
npm install gamma
Now recursively bundle up all the required modules starting at main.js into a single file with the browserify command:
browserify main.js -o bundle.js
Browserify parses the AST for require() calls to traverse the entire dependency graph of your project.
Drop a single <script> tag into your html and you're done!
<script src="bundle.js"></script>
Not only is it fun to write client-side scripts like this but browserify will bundle it all together into a nice and tidy minified single script file :D

Node app variables passed into stylus file

I am building a little node app and using Express with Jade and Stylus to render some basic HTMl pages.
I was curious if there is a way for me to pass some variables INTO the .styl file that are generated from Node? I am well aware that i can define variables inside of the .styl file but I have a need to be more dynamic. Specifically i was looking for an easy way to store some colors in the db, have node grab those values, then insert those into the .styl file so that when the page is rendered these variables are passed in. It seems like this should be do-able but i am lacking on the details. Any help is appreciated. Thanks!
Thanks to #ebohlman as his advice was close to what i ultimately implemented.
basically i was trying to figure out how to do this on top of the Connect Middleware and here is what i came up with:
when doing app.configure i used the custom compile compile function (key 'compile') like so:
app.use(require('stylus')
.middleware({
src: app.root + '/app/public',
compile: compile
})
);
then i created a couple of functions:
var stylus = require('stylus');
var mylib = function(style){
style.define('themeColor1', function(){
//call to the db that returns a color
color = 'blue';
color = color ? color : 'orange';
return new stylus.nodes.Literal(color);
});
};
var compile = function(str, path) {
return stylus(str)
.use(mylib);
};
then inside of the .styl file i do:
background-color themeColor1();
the ternary operator in the themeColor1 function allows for easy defaults and an override. It took me a bit to figure out the API based upon the examples but it seems like this COULD be a solution others would want to know how to do. If anyone has any downfalls of this approach please let me know.
You can use the Stylus API's define() function to set Stylus variables and make JS functions available to it.

Resources