• This repository has been archived on 18/Oct/2019
  • Stars
    star
    148
  • Rank 249,983 (Top 5 %)
  • Language
    CoffeeScript
  • License
    MIT License
  • Created about 13 years ago
  • Updated about 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Deprecated Asset Manager for Node.js

Piler

Build Status

Feature highlights

  • Minify and concatenate JS and CSS for fast page loads
  • Tag rendering
  • Namespaces
  • Transparent preprocessor
  • Push CSS changes to the browser using Socket.IO
  • Easy code sharing with server

Need feedback for upcoming version 0.6.0

Awesome Asset Manager for Node.js

Piler allows you to manage all your JavaScript and CSS assets cleanly and directly from code. It will concatenate and minify them in production and it takes care of rendering the tags. The idea is to make your pages load as quickly as possible.

So why create a yet another asset manager? Because Node.js is special. In Node.js a JavaScript asset isn't just a pile of bits that are sent to the browser. It's code. It's code that can be also used in the server and I think that it's the job of asset managers to help with it. So in Piler you can take code directly from your Javascript objects, not just from JavaScript files. Copying things from Rails is just not enough. This is just a one reason why Piler was created.

Server-side code:

clientjs.addOb({BROWSER_GLOBAL: {
    aFunction: function() {
        console.log("Hello I'm in the browser also. Here I have", window, "and other friends");
    }
}});

You can also tell Piler to directly execute some function in the browser:

clientjs.addExec(function() {
    BROWSER_GLOBAL.aFunction();
    alert("Hello" + window.navigator.appVersion);
});

Currently Piler works only with Express, but other frameworks are planned as well.

Piler is written following principles in mind:

  • Creating best possible production setup for assets should be as easy as including script/link to a page.
  • Namespaces. You don't want to serve huge blob of admin view code for all anonymous users.
  • Support any JS- or CSS-files. No need to create special structure for your assets. Just include your jQueries or whatever.
  • Preprocessor languages are first class citizens. Eg. Just change the file extension to .coffee to use CoffeeScript. That's it. No need to worry about compiled files.
  • Use heavy caching. Browser caches are killed automatically using the hash sum of the assets.
  • Awesome development mode. Build-in support for pushing CSS changes to browsr using Socket.IO.

Full example Express 2.x

var createServer = require("express").createServer;
var piler = require("piler");

var app = createServer();
var clientjs = piler.createJSManager();
var clientcss = piler.createCSSManager();

app.configure(function() {
    clientjs.bind(app);
    clientcss.bind(app);

    clientcss.addFile(__dirname + "/style.css");

    clientjs.addUrl("http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js");
    clientjs.addFile(__dirname + "/client/hello.js");
});

app.configure("development", function() {
    clientjs.liveUpdate(clientcss);
});

clientjs.addOb({ VERSION: "1.0.0" });

clientjs.addExec(function() {
    alert("Hello browser" + window.navigator.appVersion);
});

app.get("/", function(req, res){
    res.render("index.jade", {
        layout: false,
        js: clientjs.renderTags(),
        css: clientcss.renderTags()
    });
});

app.listen(8080);

Full example Express 3.x

var express = require('express'),
    http = require('http'),
    piler = require("piler"),
    app = express();

var clientjs = piler.createJSManager();
var clientcss = piler.createCSSManager();
var srv = require('http').createServer(app);

app.configure(function(){

    clientjs.bind(app,srv);
    clientcss.bind(app,srv);

    clientcss.addFile(__dirname + "/style.css");

    clientjs.addUrl("http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js");
    clientjs.addFile(__dirname + "/client/hello.js");
});

app.configure("development", function() {
    clientjs.liveUpdate(clientcss);
});

clientjs.addOb({ VERSION: "1.0.0" });

clientjs.addExec(function() {
    alert("Hello browser" + window.navigator.appVersion);
});

app.get("/", function(req, res){
    res.render("index.jade", {
        layout: false,
        js: clientjs.renderTags(),
        css: clientcss.renderTags()
    });
});

srv.listen(8080);

index.jade:

!!! 5
html
  head
    !{css}
    !{js}
  body
    h1 Hello Piler

Namespaces

The example above uses just a one pile. The global pile.

If you for example want to add big editor files only for administration pages you can create a pile for it:

clientjs.addFile("admin", __dirname + "/editor.js");
clientjs.addFile("admin", __dirname + "/editor.extension.js");

This will add file editor.js and editor.extension.js to a admin pile. Now you can add that to your admin pages by using giving it as parameter for renderTags.

js.renderTags("admin");

This will render script-tags for the global pile and the admin-pile. js.renderTags and css.renderTags can take variable amount of arguments. Use js.renderTags("pile1", "pile2", ....) to render multiple namespaces

Piling works just the same with css.

Sharing code with the server

Ok, that's pretty much what every asset manager does, but with Piler you can share code directly from your server code.

Let's say that you want to share a email-validating function with a server and the client

function isEmail(s) {
  return !! s.match(/.\w+@\w+\.\w/);
}

You can share it with addOb -method:

clientjs.addOb({MY: {
   isEmail: isEmail
   }
});

Now on the client you can find the isEmail-function from MY.isEmail.

addOb takes an object which will be merged to global window-object on the client. So be careful when choosing the keys. The object can be almost any JavaScript object. It will be serialized and sent to the browser. Few caveats:

  1. No circural references
  2. Functions will be serialized using Function.prototype.toString. So closures won't transferred to the client!

Pattern for sharing full modules

This is nothing specific to Piler, but this is a nice pattern which can be used to share modules between the server and the client.

share.js

(function(exports){

  exports.test = function(){
       return 'This is a function from shared module';
  };

}(typeof exports === 'undefined' ? this.share = {} : exports));

In Node.js you can use it by just requiring it as any other module

var share = require("./share.js");

and you can share it the client using addFile:

clientjs.addFile(__dirname + "./share.js");

Now you can use it in both as you would expect

share.test();

You can read more about the pattern from here

Logging

Sometimes it is nessesary to control pilers output based on the system environment your running your application in. In default mode Pilers logger will output any information it has by using the "console" javascript object. The following example shows how to configure a custom logger

Logger interface

The basic logger facility implements the following methods.

exports.debug    = console.debug
exports.notice   = console.log
exports.info     = console.info
exports.warn     = console.warn
exports.warning  = console.warn
exports.error    = console.error
exports.critical = console.error

Inject a custom logger

The following example injects "winston", a multi-transport async logging library into pilers logging mechanism.

var piler = require('piler');
var logger = require('winston');
// [More logger configuration can take place here]

global.js = js = piler.createJSManager({ outputDirectory: assetTmpDir , "logger": logger});
global.css = css = piler.createCSSManager({ outputDirectory: assetTmpDir, "logger": logger});

More information about winston can be found here.

Awesome development mode!

Development and production modes works as in Express. By default the development mode is active. To activate production mode set NODE_ENV environment variable to production.

Live CSS editing

This is really cool! You don't want to edit CSS at all without this after you try it!

Because Piler handles the script-tag rendering it can add some development tools when in development mode.

Using Express you can add Live CSS editing in development mode:

app.configure("development", function() {
   clientjs.liveUpdate(clientcss);
});

This is similar to Live.js, but it does not use polling. It will add Socket.IO which will push the CSS-changes to your browser as you edit them.

If your app already uses Socket.IO you need to add the io-object as second parameter to liveUpdate:

var io = require('socket.io').listen(app);
clientjs.liveUpdate(clientcss, io);

Script-tag rendering

In development mode every JS- and CSS-file will be rendered as a separate tag.

For example js.renderTags("admin") will render

clientjs.addFile(__dirname + "/helpers.js");
clientjs.addFile("admin", __dirname + "/editor.js");
clientjs.addFile("admin", __dirname + "/editor.extension.js");

to

<script type="text/javascript" src="/pile/dev/_global/1710d-helpers.js?v=1317298508710" ></script>
<script type="text/javascript" src="/pile/dev/admin/3718d-editor.js?v=1317298508714" ></script>
<script type="text/javascript" src="/pile/dev/admin/1411d-editor.extension.js?v=1317298508716" ></script>

in development mode, but in production it will render to

<script type="text/javascript"  src="/pile/min/_global.js?v=f1d27a8d9b92447439f6ebd5ef8f7ea9d25bc41c"  ></script>
<script type="text/javascript"  src="/pile/min/admin.js?v=2d730ac54f9e63e1a7e99cd669861bda33905365"  ></script>

So debugging should be as easy as directly using script-tags. Line numbers will match your real files in the filesystem. No need to debug huge Javascript bundle!

Examples

Visit this directory to see a simple example using ExpressJS 2.x.

This example uses ExpressJS 3.x a custom logger (winston) and a global socket.io instance together with Piler.

API summary

Code will be rendered in the order you call these functions with the exception of addUrl which will be rendered as first.

createJSManager and createCSSManager

Can take an optional configuration object as an argument with following keys.

var jsclient = piler.createJSManager({
    outputDirectory: __dirname + "/mydir",
    urlRoot: "/my/root"
});

urlRoot

Url root to which Piler's paths are appended. For example urlRoot "/my/root" will result in following script tag:

<script type="text/javascript" src="/my/root/min/code.js?v=f4ec8d2b2be16a4ae8743039c53a1a2c31e50570" ></script>

outputDirectory

If specified Piler will write the minified assets to this folder. Useful if you want to share you assets from Apache etc. instead of directly serving from Piler's Connect middleware.

JavaScript pile

addFile( [namespace], path to a asset file )

File on filesystem.

addUrl( [namespace], url to a asset file )

Useful for CDNs and for dynamic assets in other libraries such as socket.io.

addOb( [namespace string], any Javascript object )

Keys of the object will be added to the global window object. So take care when choosing those. Also remember that parent scope of functions will be lost.

You can also give a nested namespace for it

clientjs.addOb({"foo.bar": "my thing"});

Now on the client "my thing" string will be found from window.foo.bar.

The object will be serialized at the second it is passed to this method so you won't be able modify it other than between server restarts. This is usefull for sharing utility functions etc.

Use res.addOb to share more dynamically objects.

addExec( [namespace], Javascript function )

A function that will executed immediately in browser as it is parsed. Parent scope is also lost here.

addRaw( [namespace], raw Javascript string )

Any valid Javascript string.

CSS pile

These are similar to ones in JS pile.

addFile( [namespace], path to a asset file )

CSS asset on your filesystem.

addUrl( [namespace], url to a asset file )

CSS asset behind a url. Can be remote too. This will be directly linked to you page. Use addFile if you want it be minified.

addRaw( [namespace], raw CSS string )

Any valid CSS string.

Supported preprocessors

JavaScript

For JavaScript the only supported one is CoffeeScript and the compiler is included in Piler.

CSS

CSS-compilers are not included in Piler. Just install what you need using npm.

  • Stylus with nib (npm install stylus nib)
  • LESS (npm install less)

Adding support for new compilers should be easy.

Feel free to contribute!

Installing

From npm

npm install piler

Source code

Source code is licenced under The MIT License and it is hosted on Github.

Changelog

v0.4.2 - 2013-04-16

  • Fixes to work with ExpressJS 3.x
  • Unit test fixes
  • Make console output configurable

v0.4.1 - 2012-06-12

  • Add getSources
  • Put cache key to resource url instead of query string

v0.4.0 - 2012-06-17

  • Remove Dynamic Helpers.

Dynamic Helpers where an Express 2.0 only API. This makes Piler more framework agnostic and it will work with Express 3.0. This also removes support for response object functions. We'll add those back if there is a need for them (open up a issue if you miss them!) and we'll find good framework agnostic way to implement them.

v0.3.6 - 2012-06-17

  • Bind all production dependency versions

v0.3.5 - 2012-06-17

  • Fix LESS @imports
  • Fix Stylus without nib
  • Use path module for Windows compatibility

v0.3.4 - 2012-03-29

  • Fix Stylus @imports

v0.3.3 - noop

v0.3.2 - 2011-12-11

  • Workaround compiler bug in CoffeeScript

v0.3.1 - 2011-11-17

  • Fix CSS namespaces

v0.3.0 - 2011-10-13

  • Rename to Piler
  • Really minify CSS
  • Implemented res.addOb
  • Implement outputDirectory and urlRoot options.
  • addOb can now take nested namespace string and it won't override existing namespaces.

Contact

Questions and suggestions are very welcome

More Repositories

1

underscore.string

String manipulation helpers for javascript
JavaScript
3,367
star
2

react-zorm

πŸͺ± Zorm - Type-safe <form> for React using Zod
TypeScript
714
star
3

node-hbsfy

Handlebars precompiler plugin for Browserify
JavaScript
257
star
4

immer-reducer

Type-safe and terse reducers with Typescript for React Hooks and Redux
TypeScript
225
star
5

slimux

SLIME inspired tmux integration plugin for Vim
Vim Script
217
star
6

redux-hooks

βš“ React Hooks implementation for Redux
TypeScript
96
star
7

node-promisepipe

Safely pipe node.js streams while capturing all errors to a single promise
JavaScript
80
star
8

requirejs-hbs

Simple Handlebars loader plugin for RequireJS
JavaScript
78
star
9

lean-redux

Redux state like local component state
JavaScript
78
star
10

angry-caching-proxy

Make package downloads lightning fast!
JavaScript
77
star
11

browserify-externalize

Create external Browserify bundles for lazy asynchronous loading
JavaScript
73
star
12

postcss-ts-classnames

PostCSS plugin to generate TypeScript types from your CSS class names.
TypeScript
70
star
13

jslibs

List of Javascript libraries
59
star
14

backbone.viewmaster

Few tested opinions on how to handle deeply nested views in Backbone.js focusing on modularity.
JavaScript
52
star
15

babel-plugin-ts-optchain

Babel plugin for transpiling legacy browser support to ts-optchain by removing Proxy usage.
TypeScript
30
star
16

trpc-cloudflare-worker

TypeScript
29
star
17

carcounter

Asynchronous module loading example with Browserify
JavaScript
24
star
18

redux-render-prop

Redux with render props. Typescript friendly.
TypeScript
22
star
19

source-map-peek

Peek into original source via source maps from the command line when devtools fail.
JavaScript
21
star
20

TextareaServer

Server for opening external text editors from Chrome
CoffeeScript
19
star
21

deno_karabiner

Write Complex Modifications for Karabiner-Elements using Typescript and Deno.
TypeScript
17
star
22

babel-plugin-display-name-custom

display name inference for your custom react component creators
JavaScript
15
star
23

geekslides

Remote controllable Node.js introduction slides
JavaScript
15
star
24

npm-release

Github action for npm (pre)releases
TypeScript
15
star
25

sauna.reload

Development & Issues MOVED to https://github.com/collective/sauna.reload
Python
13
star
26

TextareaConnect

Edit textareas in Google Chrome using any external editor!
CoffeeScript
13
star
27

node-clim

Console.Log IMproved for Node.js
JavaScript
12
star
28

react-simple

simple style only components for the web & native
JavaScript
9
star
29

typescript-redux-todoapp

Type-safe Boilerplate-free Redux Example
TypeScript
9
star
30

jquery.panfullsize

jQuery plugin for panning large images
JavaScript
8
star
31

neovim-config

Vim Script
8
star
32

Projectwatch

Watch file changes and run multiple css/js pre-processors from one watcher
JavaScript
8
star
33

multip

Tiny multi process init for containers written in Rust πŸ¦€
Rust
8
star
34

ts-box

Put exceptions into boxes πŸ“¦
TypeScript
8
star
35

vimconfig

Vim and other dotfiles
Vim Script
7
star
36

node-tftp

Streaming TFTP Server for node.js
JavaScript
7
star
37

yalr

YALR - Yet Another Live Reload
JavaScript
6
star
38

react-makefile

Makefile boilerplate for React.js
JavaScript
6
star
39

vscode-unsaved

Makes you actually notice when you have unsaved files
TypeScript
5
star
40

reallyexpress

Really Express extends Express with extraordinary features given by Node.js. Work in progress.
CoffeeScript
5
star
41

shell-cheatsheet

4
star
42

tmpshare

Easily share temporary files over http
JavaScript
4
star
43

ircshare

Simple service for sharing your pictures on IRC
JavaScript
3
star
44

qdomain

Promises from domains
JavaScript
3
star
45

ircshare-android

Share pictures easily in IRC from Android phone
Java
3
star
46

browserify-cs-example

Browserify v2 with CoffeeScript Source Maps
CoffeeScript
3
star
47

flysight-subtitles

Convert FlySight data files (.csv) to SubRip (.srt) subtitles.
JavaScript
3
star
48

node-handlebars-runtime

Handlebars runtime only
JavaScript
2
star
49

node-lights

Instanssi Light Server Simulator
CoffeeScript
2
star
50

flips.io

JavaScript
2
star
51

revisioncask

Version control management made simple
Python
2
star
52

subssh

Small framework for creating SSH public key based shell accounts.
Python
2
star
53

toggl-paster

I need to paste Toggl time entries into things so I made a thing.
TypeScript
2
star
54

utils

Epeli's Javascript / Typescript utilities
TypeScript
2
star
55

MAILNETD

Meta Asynchronous Irc Linked Network Email Transport Daemon
Python
1
star
56

rt

Instant tab-complete for npm scripts and Jakefiles
Rust
1
star
57

lunarvim-config

Lua
1
star
58

awesome

My Personal Awesome WM config
Lua
1
star
59

wp-graphql-todoapp

TypeScript
1
star
60

stylify

JavaScript
1
star
61

subssh_buildout

buildout for subssh development purposes
Python
1
star
62

rollsum

Just experiments with rolling checksums. Nothing to see here.
C
1
star
63

sh-thunk

Generate promise returning thunks from shell strings.
JavaScript
1
star
64

LightManager

lightmanager tool written for instanssi.org party
Java
1
star
65

konf

TypeScript
1
star
66

HAL2012

Home hack using Node.js and Raspberry Pi
CoffeeScript
1
star
67

IRCPost

Simple IRC bot with HTTP POST API
CoffeeScript
1
star
68

blog

JavaScript
1
star
69

aswyg-editor

ASWYG Editor - Also See What You Get Editor
JavaScript
1
star