Stylus and CoffeeScript middleware automatically compile any Stylus and CoffeeScript code for you without having to restart your app, eg you can edit a .styl file and just refresh the page in your browser and your changes will be there. I find this to be very convenient while developing, but would that severely effect the end-user's page load time in production?
My Express setup is usually something like this (CoffeeScript):
app = express()
app.set 'views', __dirname + '/views'
app.set 'view engine', 'jade'
compile = (str, path) -> return stylus(str).set 'filename', path
app.use stylus.middleware {
src: __dirname + '/stylus',
dest: __dirname + '/assets/css',
compile: compile
}
app.use coffee {
src: __dirname + '/coffee',
dest: __dirname + '/assets/js',
encodeSrc: false
}
app.use express.static __dirname + '/assets'
It will definitely be slower than serving the pre-compiled files statically (if Stylus and CoffeeScript don't support caching which I don't know). The question is, whether this matters. And this depends on the intensity of the traffic your app receives.
In general, I would suggest to pre-compile your files and serve it statically. For the deployment, I would suggest to use something like Gulp.js and watch your files. With gulp your files can be automatically compiled on file changes which is most of the time better than compiling it when the files are requested.
Related
I have a project that uses Nib and Stylus on Express server, and after some changes this compilation process from .styl to .css didn't work anymore, I was looking in documentation of Nib, Stylus and Express but I can't find an answero to problem because my code, file directory and settings seems ok. But still doesn't compile.
Code:
express = require("express")
coffee = require("coffee-script")
stylus = require("stylus")
jade = require("jade")
nib = require("nib")
app = express.createServer()
port = process.env.PORT || 3000
app.use app.router
app.use express.methodOverride()
app.use express.bodyParser()
app.set "views", __dirname + "/views"
app.set "view engine", "jade"
app.use stylus.middleware(
src: __dirname + "/src"
dest: __dirname + "/public"
compile: (str, path) ->
stylus(str).set("filename", path).set("warn", true).set("compress", false).set("paths", [ require("stylus-blueprint") ]).use nib()
)
app.listen port
After looking into documention, Github issues, I can't understand what changes have been made to stop working. So, my question, how or what I should be looking for to try resolve this problem?
Thanks for the help in advance.
It would be useful if you provided a error output/log and a cakefile.
Also you might want to look into using connect-assets. A good example of usage is in the express-coffee template.
I have decided to use ExpressJS with CoffeeScript and Stylus. Usually when I work with CoffeeScript, I do a coffee --watch and something similar for Compass/SASS. Here, since CoffeeScript and Stylus are available as a NPM package, I was thinking if its possible to write CoffeeScript and Stylus and have Node/Express compile them when required? This way I wont need a watcher anymore.
Also when I create an express app using express -c stylus, in app.js I get additional:
app.use(require('stylus').middleware({ src: __dirname + '/public' }));
What does it actually do? It doesn't appear to compile my CSS? When I put
body
background: red
into the default style.styl file, restart server, it doesn't appear to show
Ok so theres connect-assets for this exact purpose. Now I am still looking for something for server side ...
try to set
var stylus = require('stylus');
app.use(stylus.middleware({
src: __dirname + '/public',
compile: function(str, path) {
return stylus(str)
.set('filename', path)
.set('compress', false)
.set('warn', true);
}
}));
This compile function is not required, but without it the styl files don't get compiled..
Since Twitter Bootstrap 2 is out, I wanted to integrate that into my Node.js project. Unfortunately, there's something wrong with the less compiler and I can't get it to work. I put all files into the public folder and set up a new project with express -c less newproj. and added the lines for less
less = require('less');
app.use(express.compiler({ src: __dirname + '/public', enable: ['less'] }));
All Node tells me is:
Express server listening on port 3000 in development mode
undefined
On the client side I get a 500 (Internal Server Error) for the bootstrap.css file, which should be compiled by lessc.
lessc bootstrap.less
Works fine.
Anybody knows how to solve the issue?
For posterity, this has changed a lot in recent Express:
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
// This is just boilerplate you should already have
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
Ok, here is what I have found for you.
First you need both the compiler and the static middleware. The compiler compiles your less and recompiles on changes, the static middleware does the actual serving of the css
app.use(express.compiler({ src : __dirname + '/public', enable: ['less']}));
app.use(express.static(__dirname + '/public'));
Second, for some reason when the compiler runs it is losing the current path information, so it can't find the includes. So I had to go through the bootstrap.css and add the path to each import.
#import "/public/stylesheets/reset.less";
This is clearly odd, I am going to dig into it further.
Edit: While odd, a deep look through the code shows me no simple way around it. A bit more searching found this pull request on the connect repo https://github.com/senchalabs/connect/pull/174 which offers a fix for this, but the devs don't seem to want it.
There are also some workarounds in that thread, but it seems the best idea is to absolute path your includes.
app.js:
app.use(express.compiler({ src: __dirname + '/public', enable: ['less']}));
app.use(express.static(__dirname + '/public'));
In my jade view:
link(rel="stylesheet", type="text/css", href='/app/stylesheets/app.less)
I've got less file in:
public/app/stylesheets/app.less
When I request the page I've got in html head:
<link href="/app/stylesheets/app.less" type="text/css" rel="stylesheet">
And noting in server console.
1) So Why does express even doesn't try to compile app.less? Should it?
2) If everything right: should link in htm be
<link href="/app/stylesheets/**app.less**" ... >
or express should change the file's extension while render?
<link href="/app/stylesheets/**app.css**" ... >
?
It seems that compiler() was removed from connect and it won't be supported anymore, according to TJ Holowaychuck (creator of Connect & Express):
https://github.com/visionmedia/express/issues/877
Update 2013-01-16
As of Express 3.0.0 the framework now includes less-middleware instead of the compiler middleware that used to be in Connect. It works much the same way as the old middleware.
To add it to an existing project, add less-middleware to your package.json and run npm install then add the following to your config:
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
In your Jade template you reference it as a normal CSS file:
link(rel='stylesheet', type='text/css', href='css/styles.css')
Your directory structure will look something like this:
myapp
+-public
+-css
+-styles.less
less-middleware will look for .less files that have the same name as the .css file that was requested. If it finds one it will compile it and server the resulting CSS.
You'll probably want to exclude compiled CSS files from your source control. If you're using Git you can add .css to your .gitignore file.
You can get LESS compiling to work via middleware, the same way that Stylus currently works.
Edit: Instead of trying to get the [pull request][0] into the main LESS repository it was decided to just do it as a separate package.
Here is how you can use the LESS.js middleware:
var lessMiddleware = require('less-middleware');
var app = express.createServer();
app.configure(function () {
// Other configuration here...
app.use(lessMiddleware({
src: __dirname + '/public',
compress: true
}));
app.use(express.static(__dirname + '/public'));
});
In your jade file you should then be able to use the reference to the css file:
link(rel="stylesheet", type='text/css', href='/app/stylesheets/app.css')
What I would like to do is add the following to me already running coffeescript written server
app.get '/test.js', (req, res) ->
render coffee somecoffeefile.coffee
Is something like this possible with NodeJS, Express, and Coffeescript?
Thanks!
Jose
Good news: This is already comes with Connect (and therefore Express, which extends Connect) as a plugin! It's not well-documented; in fact, I wrote something similar myself (connect-coffee) before I was informed that such a thing already existed.
Here's how you'd go about setting it up with Express:
# Notice the following code is coffescript
# You must add the parens for the app.use method to use in js
coffeeDir = __dirname + '/coffee'
publicDir = __dirname + '/public'
app.use express.compiler(src: coffeeDir, dest: publicDir, enable: ['coffeescript'])
app.use express.static(publicDir)
Now when, say, http://yourapp/foo.js gets requested, if no such file exists in your public directory, foo.coffee will automatically be compiled, and the resulting foo.js will be served. Note that it's important for static to be set up after compiler.
Update: As of Connect 1.7, the compiler middleware has been removed. Partly because of that, and partly to provide a more Rails 3.1-like experience, I've created a new middleware called connect-assets. Install it with npm, then set it up like so:
app.use require('connect-assets')(directory)
where directory is the folder your CoffeeScript files are in (the default is assets). Simple, right? Try it out and let me know what you think.
CoffeeScript = require 'coffee-script'
app.get '/test.js', (req, res) ->
render CoffeeScript.compile coffeeSourceCode
For some reason, the compiler isn't working anymore, so I did this:
fs = require 'fs'
coffee = require 'coffee-script'
app.use express.static "#{__dirname}/static"
app.get '/:script.js', (req, res) ->
res.header 'Content-Type', 'application/x-javascript'
cs = fs.readFileSync "#{__dirname}/coffee/#{req.params.script}.coffee", "ascii"
js = coffee.compile cs
res.send js
Now you can code up coffee/animal.coffee and in your html, do a standard script src='/animal.js'. This hides the implementation detail. The coffeescript is not accessible because "/coffee" dir is not exposed as a static path.
Notes:
This is, of course, a CoffeeScript Node app. I assume if you're using CS for client scripts, you're using it for your server too!
The "static" line is optional. My point is you can happily keep "js" files in the static dir, e.g. library files like jquery.min.js.
Like most Node/Express examples, this is good for development; but for production, you should send cache headers, compress it, and ideally some form of reverse-proxying to avoid reading the file and compiling it each time.
For those of us using the latest version of Connect and Express, I've just published a new module, npm install connect-coffee-script, which compile coffee script files on the fly. Documentation and a sample are provided as well as an introduction article.
Here's an exemple from the readme:
var coffeescript = require('connect-coffee-script');
var connect = require('connect');
var app = connect();
app.use(coffeescript({
src: __dirname,
dest: __dirname + '/public',
bare: true
}));
app.use(connect.static(__dirname + '/public'));
app.listen(3000)
If you would like to use a great existing plugin I would recommend Trevor Burnham's Connect-Assets. It helps compiling, minifying and concatenating .js and .coffee-files and optimizes how the files are being served (a far-future expires header with invalidation using the file's md5-hash). Well written plugin.
coffee-middleware did exactly what I wanted to - minimal setup, no generated files, and not sloppy.
When it gets a request for somescript.js it will check if there is a somescript.coffee. If there is, it will compile it and send it over.
Install it:
npm install coffee-middleware
To use, just add
app.use require('coffee-middleware') src: "#{__dirname}/your/web/root"
before whatever you use to serve static files.
Simple example that serves files in a "public" directory, complies coffeescript before sending it over, and does colored logging:
app = require('express')()
app.use require('morgan') 'dev'
app.use require('coffee-middleware') src: "#{__dirname}/views"
app.use require('serve-static') "#{__dirname}/views"
app.listen 80
To use above code:
mkdir coffeeServer
cd coffeeServer
npm install morgan coffee-middleware serve-static
npm install coffee-script -g
echo 'app = require("express")()
app.use require("morgan") "dev"
app.use require("coffee-middleware") src: "#{__dirname}/views"
app.use require("serve-static") "#{__dirname}/views"
app.listen 80' > server.coffee
coffee -c server.coffee
mkdir views
cd views
echo 'console.log "Hello world!"' > script.coffee
cd ..
node server.js
You can copy the whole bunch into the terminal and it will setup and run the server.
To test:
curl XXX.XXX.XXX.XXX/script.js
That last bit should spit out
(function() {
console.log("Hello world!");
}).call(this);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyaXB0LmpzIiwic291cmNlcyI6WyJzY3JpcHQuY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQUEsRUFBQSxPQUFPLENBQUMsR0FBUixDQUFZLGNBQVosQ0FBQSxDQUFBO0FBQUEifQ==NHS0076
Good luck!
I think you should compile COFFEE files only once, especially with production mode
If you want use coffee with Express 3, or with any web framework look to this repo ExpressOnSteroids You can use this solution, or create your own with Cakefile from this project
You can use Coffee4Clients to render coffee assets to javascript on the fly with your express server.
Update: Coffee4Clients has been killed in favour of DocPad which pre-compiles your assets.