Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
In the year 2013, why do we still organize our web assets like it's 1990, grouping them together in big directories separated by their type? Instead, why don't we leverage directories a bit more effectively to put files together that really belong together? For example, why don't we put JavaScript and stylesheet assets that are just used by one particular page in the same directory as that page's template? And what about related assets like personModel.js, personView.js, person.css, etc.? Why don't we keep those together in a single "person" directory, instead of spreading them out all over the place? It sure would be nice to be able to quickly switch between those files!
One of the obstacles, besides resistance to change, has been that asset management has a lot of moving parts. A complete general solution needs to address preprocessing (i.e. compiling .scss, .coffee, etc.) for arbitrary asset types, minification and concatenation in production mode, and dependency management.
Cartero works on top of Grunt.js and together with package managers like Bower, addressing these issues so that we can more effectively organize assets, optimize their delivery, and scale up applications.
<script>
and <link>
tags are generated for you.
Cartero is JavaScript framework, stylesheet and templating language agnostic. It also almost works with any web framework – the very small "hook" of runtime logic is easy to port to any web framework, but is currently only available for Node.js / Express. Instructions for writing a Hook for another framework are below.
Often times assets are just used by one particular page. Just keep those assets in the same directory as the page's template, and they will be automatically be included when it is rendered. No more messing with <script>
and <link>
tags! For example, say your page templates live in a directory named views
, as is typical for most web frameworks.
views/
login/
login.jade
login.coffee
login.scss
When the login.jade
template is rendered, the compiled login.coffee
and login.scss
assets will automatically be included. A page can also "extend" on the assets required by another page.
Some assets are needed by many different pages and / or are supplied by third parties. Keep all of these common assets in one or more Asset Libraries, grouped into subdirectories, called Bundles, that may contain JavaScript files, stylesheets, templates, and even images. Additionally, each bundle may have meta-data such as any dependencies on other bundles. Take the following example library:
assetLibrary/
JQuery/
jquery.js
Backbone/
backbone.js
Person/
person.coffee
person.scss
person.tmpl
Here, the Person bundle might depend on the Backbone bundle, which in turn depends on the JQuery bundle. Dependencies can be specified in bundle.json
files that live in bundle directories themselves, or in an external bundle meta-data file. When a page requires a bundle, dependencies are automatically resolved. Setup your dependencies, require your bundles, and each page loads with the exact set of assets that it needs.
The heart of Cartero is an intelligent Grunt.js task that ties together other Grunt.js tasks. You configure and call the Cartero Grunt Task from your application's gruntfile. You specify exactly which preprocessing and minification tasks your application needs, and those tasks are then called by the Cartero task at the appropriate times. After the Cartero task is finished, all of your assets will be preprocessed, and, in production mode, concatenated and minified. Additionally, the Cartero task generates a cartero.json
file that enumerates the assets required for each of your page templates.
There is also a very small but important piece of logic for serving up assets and injecting them into rendered HTML, called the Hook. The Hook needs to reside in your web application framework, since it is used at the time your templates are rendered. Currently there is a Hook available only for Node.js / Express, but there is minimal logic involved and it is easy to implement in any environment. Each time you render a template, the Hook is used to look up the template in the cartero.json
file generated by the Cartero Grunt Task, and place raw HTML into three variables that are exposed to the template:
cartero_js
- the raw HTML of the <script>
elements that load all the required JavaScript files.
cartero_css
- the raw HTML of the <link>
elements that load all the required CSS files.
cartero_tmpl
- the raw, concatenated contents of all the required client side template files.
You may then output the contents of those variables in the appropriate places in your template just like any other template variable. For example, if you are using Jade templates, your page structure might look like this:
// page layout
doctype 5
html(lang="en")
head
title myPage
| !{cartero_js}
| !{cartero_css}
body
| !{cartero_tmpl}
h1 Hello World
First, install Cartero via npm:
npm install cartero
Now configure the Cartero Grunt Task in your applcation's gruntfile. (If you haven't used Grunt before, read this first.) Here is the minimal configuration that is required to run the Cartero Grunt Task (all options shown are required):
// example gruntfile
module.exports = function( grunt ) {
grunt.initConfig( {
cartero : {
options : {
projectDir : __dirname, // the root directory of your project. All other paths
// in these options are relative to this directory.
library : {
path : "assetLibrary/" // the relative path to your Asset Library directory.
},
views : {
path : "views/", // the directoy containing your server side templates.
viewFileExt : ".jade" // the file extension of your server side templates.
}
publicDir : "static/", // your app's "public" or "static" directory (into
// which processed assets will ultimately be dumped).
tmplExt : ".tmpl", // the file extension(s) of your client side template.
mode : "dev" // "dev" or "prod"
}
// `dev` target uses all the default options.
dev : {},
// `prod` target overrides the `mode` option.
prod : {
options : {
mode : "prod"
}
}
}
} );
grunt.loadNpmTasks( "cartero" );
grunt.loadNpmTasks( "grunt-contrib-watch" ); // for `--watch` flag
};
The Cartero Grunt Task also takes options that allow you to call arbitrary preprocessing and minification tasks (to compile .scss, uglify JavaScript, etc.), and more. See the reference section for a complete list of options for the Cartero task.
Once you have configured the Cartero Grunt Task, you need to configure the Hook in your web framework. As of this writing there is only a Hook available for Node.js / Express, which is implemented as Express middleware. To install it, run:
npm install cartero-express-hook
Then use
it, passing the absolute path of your project directory (i.e. the projectDir
option from the gruntfile configuration).
// app.js
var app = express();
var carteroMiddleware = require( "cartero-express-hook" );
// ...
app.configure( function() {
app.set( "port" , process.env.PORT || 3000 );
app.set( "views" , path.join( __dirname, "views" ) );
app.use( express.static( path.join( __dirname, "static" ) ) );
// ...
app.use( carteroMiddleware( __dirname ) ); // install the Cartero Hook
} );
Now you are ready to go. To let Cartero know which asset bundles are required by which pages, you use Directives. The Cartero Grunt Task scans your page template files for these Directives, which have the form ##cartero_xyz
. The ##cartero_requires
Directive is used to declare dependencies:
// peopleList.jade
// ##cartero_requires "Dialogs/EditPersonDialog"
doctype 5
html(lang="en")
head
title login
| !{cartero_js}
| !{cartero_css}
body
| !{cartero_tmpl}
h1 People List
// ...
When you run either of the following commands from the directory of your gruntfile:
grunt cartero:dev --watch
grunt cartero:prod
The Cartero Grunt Task will fire up, process all of your assets, and put the cartero.json
file used by the Hook in your project folder. The dev
mode --watch
flag tells the Cartero Grunt Task to watch all of your assets for changes and reprocess them as needed. In prod
mode, the task will terminate after minifying and concatenating your assets. In either mode, when you load a page, the three variables cartero_js
, cartero_css
, and cartero_tmpl
with be available to the page's template, and will contain all the raw HTML necessary to load the assets for the page.
options : {
// (required) The root directory for the project. ALL OTHER PATHS IN THE REMAINDER
// OF THESE OPTIONS SHOULD BE RELATIVE TO THIS DIRECTORY.
"projectDir" : __dirname,
// (required) An object that specifies your Asset Library directory and related options.
// You may also supply an array of objects, instead of just one object, if you have multiple
// directories that contain bundles. For example, if you are using Bower, you will likely
// want to include both the Bower "components" directory and an application specific
// directory in your Asset Library, so the library option would be an array of two objects.
"library" : {
// (required) The relative path to the directory containing asset bundles.
path : "assetLibrary/",
// (default: true) When true, parent bundles are automatically added as a
// dependency to their children. For example, the `Dialogs/EditPersonDialog`
// bundle would automatically depend on the `Dialogs` bundle, with no need
// to explicitly declare the dependency.
childrenDependOnParents : true,
// (default: /^_.*/) Files contained in directories with names matching this regular
// expression will be treated as part of the parent directory. This feature
// enables you to use directories within a bundle for organizational purposes,
// when otherwise they would be considered their own bundles.
directoriesToFlatten : /^_.*/,
// (default: undefined) If you can't, or would rather not, define your bundle
// properties in `bundle.json` files that live in each bundle's directory, you can
// define your bundle properties using this option. For instance, if you are using
// Bower, you are not allowed to modify the contents of its `components` directory, so
// you can use this option to provide bundle meta-data instead of `bundle.json` files.
// This option expects a hash that maps bundle names to bundle meta-data objects,
// as described below in the bundle.json reference section.
bundleProperties : grunt.file.readJSON( "bundleProperties.json" ),
// (default: undefined) If your Asset Library has multiple directories, you
// may supply this property to give this directory a unique "namespace". For
// example, if your Asset Library is composed of Bower's "components" directory
// and your own "assetLibrary" directory, you might give the "components" directory
// the "Bower" namespace. Bundles in that directory would then be referenced by
// pre-pending `Bower/` to their name.
namespace : "App"
},
// (required) An object that specifies your views directory and related options.
// As with the `library` option, you may supply an array of objects, instead
// of just one object, if you have multiple directories that contain views.
"views" : {
// (required) The path to the directory containing your server side view templates.
path : "views/",
// (required) The file extension of your server side template files (e.g. ".nunjucks"
// ".erb", ".twig", etc.). Files that match this extension are scanned for the
// ##cartero_requires directive (see below discussion of directives for more info).
viewFileExt : ".jade",
// Files or directories with names matching these regular
// expressions will be completely ignored by Cartero.
filesToIgnore : /^_.*/, // (default: /^_.*/)
directoriesToIgnore : /^__.*/, // (default: /^__.*/)
// (default: /^_.*/) Assets in flattened directories are served with a server side
// template when it is rendered, just as if they lived in the template's directory.
directoriesToFlatten : /^_.*/,
// (default: undefined) Analogous to its counterpart in the `library` option.
namespace : "Main"
}
// (required) The "public" directory of your application, that is, the directory that
// is served by your web server. In Node.js / Express applications this is generally the
// "static" directory. Cartero will automatically create directories within `publicDir`
// into which processed assets will be dumped, named (by default) `library-assets` and
// `view-assets`, containing assets that pertain to bundles and page views, respectively.
"publicDir" : "static/",
// (required) Either "dev" or "prod". In "dev" mode a) the `minificationTasks` are not run
// b) assets are not concatenated, and c) if the `--watch` flag is set, after finishing, the
// Cartero Grunt Task will watch all of your assets for changes and reprocess them as needed.
"mode" : "dev",
// (default: undefined) An array of "preprocessing tasks" to be performed on your assets,
// such as compiling scss or coffee. You may include an entry for any task in this array, AS
// LONG AS THE TASK IS AVAILABLE AND REGISTERED using `grunt.loadNpmTasks`, just as if you were
// to run the task yourself from your gruntfile.
"preprocessingTasks" : [ {
name : "coffee", // (required) The name of the task. *The task needs to be loaded.*
inExt : ".coffee", // (required) The task is run on files with this file extension.
outExt : ".js", // (optional) A new file extension to be given to processed files.
options : { // (optional) An `options` object to pass on directly to the task.
sourceMap : true // This property can also be a function that returns an object. The
} // function is passed the current srcDir and destDir of the task.
}, {
name : "sass",
inExt : ".scss",
outExt : ".css"
} ],
// (default: undefined) An array of "minification tasks" to be performed on your assets
// *in prod mode only*, such as minifying CSS or JavaScript. This option is structured
// just like the `preprocessingTasks` option.
"minificationTasks" : [ {
name : "htmlmin",
inExt : ".tmpl",
// no `outExt` means that processed files will still have the `.tmpl` extension
options : {
removeComments : true
}
}, {
name : "uglify",
inExt : ".js",
options : {
mangle : false
}
} ],
// (default: false) Cartero includes built in support for CommonJS style modules thanks
// to Browserify. Set this option to `true` to automatically "browserify" your files.
// (Also please see the `##cartero_browserify_executeOnLoad` directive below for important
// information on using this option.)
browserify : true
}
Each of your bundles may contain a bundle.json
file that specifies meta-data about the bundle, such as dependencies. (Note: An actual bundle.json file, since it is simple JSON, can not contain JavaScript comments, as does the example.) By using the bundleProperties
grunt taks option, you can alternatively specify this meta-data for all bundles in a central location.
// Sample bundle.json file
{
// (default: undefined) An array of bundles that this bundle depends on.
"dependencies" : [ "JQuery" ],
// (default: undefined) If supplied, ONLY assets listed in this array will be
// included when this bundle is required. If not supplied, all assets are included.
"whitelistedFiles" : [ "backbone.js" ],
// (default: undefined) Files in this array will be served before any other files
// in the bundle, in the order they appear in the array.
"filePriority" : [ "backbone.js" ],
// (default: undefined) An array of directories that overrides the corresponding
// property in the `library` option of the Cartero Grunt Task for this bundle only.
"directoriesToFlatten" : [ "mixins" ],
// (default: false) If true, assets in flattened subdirectories are served before
// assets in the root directory of the bundle. Otherwise, they are served afterwards.
"prioritizeFlattenedDirectories" : false,
// (default: false) This option can be used to compile separate combined asset files
// for this bundle in `prod` mode, instead of lumping them all together with rest of the
// concatenated assets for the page being served. It is useful for optimizing page load
// time. Large libraries like jQueryUI, for example, can be set as keepSeparate, so that
// they are loaded in parallel with the rest of your assets, and so that browsers
// can cache them between page loads. Note that setting this property to `true` does not
// guarantee that this bundle's files will *always* be kept totally separate. Under some
// circumstances it is not possible to keep the files separate while honoring the
// order in which assets should be served (e.g. when several `keepSeperate` bundles
// depend on a not `keepSeperate` bundle). In these cases, the bundles files are
// kept "as separate as possible" - trust us, we did think it through.
"keepSeparate" : true,
// (default: undefined) An array of files that will only be served in `dev` mode, and
// that will be ignored in `prod` mode.
"devModeOnlyFiles" : [ "mixins/backbone.subviews-debug.js" ],
// (default: undefined) Just like `devModeOnlyFiles` but for `prod` mode.
"prodModeOnlyFiles" : [ "mixins/backbone.subviews.js" ],
// (default: undefined) An array of files that should be included when the bundle is
// sourced (i.e. copied to the public folder), but that should not be concatenated with
// any other assets or served by the Hook. This feature allows you to accommodate
// ".css" or ".js" files that are "dynamically loaded" after the initial page load.
"dynamicallyLoadedFiles" : [ "ie-8.css" ],
// Only to be used when the `browserify` option in the Cartero Grunk Task is enabled,
// this property is an array of JavaScript files that should be executed as soon as they
// are loaded in the client. Files that are not included in this property will not
// be executed until they are `require`d by another file.
"browserify_executeOnLoad" : [ "backbone.js" ]
}
This Directive is used in server side templates to specify which bundles they require. Bundles are referred to by their name, which is the full path of their folder, relative to the Asset Library directory in which they reside. If the Asset Library directory has a namespace
property, that namespace should be pre-pended to the bundle name. Generally you will want to enclose the Directive in a "comment" block of whatever template language you are using, as shown here (.erb syntax).
<%# ##cartero_requires "App/Dialogs/EditPersonDialog" %>
<%# All dependencies are automatically resolved and included %>
This Directive is used in server side templates to specify that one template should "inherit" all of the assets of another. parentView must be a path relative to the view directory (pre-pended with the view directory's namespace
, if it has one).
<%# ##cartero_extends "layouts/site_layout.twig" %>
When your assets are processed, this Directive is replaced with the path of the directory in which it appears. It is similar in concept to the node.js global __dirname
, but the path it evaluates to is relative to your application's publicDir
.
var templateId = "##cartero_dir";
It can be used in any type of asset processed by Cartero, including client side template files.
<script type="text/template" id="##cartero_dir">
...
</script>
When the browserify
option in the Cartero Grunk Task is enabled, this directive is used in JavaScript files to specify that they should be automatically executed when they are loaded. You will definitely want to include this directive in your "main" JavaScript files for each page, since otherwise they would never be executed!
The heart of Cartero is an intelligent Grunt.js task, and can be used with any web framework. However, there is a small piece of logic called the Hook which must be called from your web framework, since it is used when each page is rendered. If you are interested in developing a Cartero Hook for your web framework of choice, keep reading - it's not hard.
From a high level perspective, the Hook is responsible for populating the cartero_js
, cartero_css
, and cartero_tmpl
variables and making them available to the template being rendered. The implementation details are somewhat dependent on your web framework, but the general idea will always be similar.
projectDir
.cartero.json
file that was generated by the Cartero Grunt Task, located in the projectDir
, to lookup the assets needed for the template being rendered. The cartero.json
file has the following format. All paths in the file are relative to projectDir
.// Sample catero.json file
{
// the relative path of the `publicDir`
publicDir : "static",
parcels : {
// A template's "parcel" is the collection of assets required when it is rendered. Parcels
// are named using the relative path of their corresponding template file.
"views/peopleList/peopleList.jade" : {
// `js`, `css`, and `tmpl` are the relative paths of the assets in this parcel.
js : [
"static/library-assets/JQuery/jquery.js",
"static/library-assets/JQueryUI/jquery-ui.js",
// ...
"static/view-assets/peopleList/peopleList.js"
],
css : [
"static/library-assets/JQueryUI/jquery-ui.css",
// ...
"static/view-assets/peopleList/peopleList.css"
],
tmpl : [
"static/library-assets/Dialogs/EditPersonDialog/editPersonDialog.tmpl"
]
},
// ...
}
}
cartero_js
, cartero_css
, and cartero_tmpl
template variables. For the case of js
and css
files, it just needs to transform the paths in the cartero.json
file to be relative to the publicDir
, and then wrap them in <script>
or <link>
tags. For tmpl
assets, the Hook needs to read the files, concatenate their contents, and then put the whole shebang into cartero_tmpl
.Yes. The name of the concatenated asset files generated in prod
mode includes an MD5 digest of their contents. When the contents of one of the files changes, its name will be updated, which will cause browsers to request a new copy of the content. The Rails Asset Pipeline implements the same cache busting technique.
Yes. Use the Grunt --force
flag.
grunt cartero:dev --force --watch
EMFILE means you've reached the OS limit of concurrently open files. There isn't much we can do about it, however you can increase the limit yourself.
Add ulimit -n [number of files]
to your .bashrc/.zshrc file to increase the soft limit.
If you reach the OS hard limit, you can follow this StackOverflow answer to increase it.
prod
mode, won't image urls used in my stylesheets break?Yes and No. They would break, but Cartero automatically scans your .css
files for url()
statements, and fixes their arguments so that they don't break.
If you develop a Hook for your web framework, please let us know and we'll add it to the directory.
##Change Log
See the CHANGELOG.md file.
By Oleg Seletsky and David Beck.
Copyright (c) 2013 Rotunda Software, LLC.
Licensed under the MIT License.
v0.1.1
FAQs
Modular front end development for the masses. Built on npm and browserify.
The npm package cartero receives a total of 80 weekly downloads. As such, cartero popularity was classified as not popular.
We found that cartero demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 9 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.