Giter Club home page Giter Club logo

cartero's Introduction

DEPRECIATION NOTICE: At long last, cartero has been depreciated. As the first multi-page application build tool, cartero served its purpose well for many years. However now there are far more robust and better supported tools that can be used to achieve the same goals. We recommend migrating any projects still using cartero to Web Pack. Thank you to everyone who contributed to this pioneering project.

cartero

cartero is an asset pipeline built on npm and browserify that allows you to easily organize front end code in multi-page web applications into reusable packages containing HTML, JavaScript, css, and images.

Build Status

Overview

cartero eliminates much of the friction involved in the build process when applying modular design principles to front end assets in multi-page web applications. Use directories to group together assets (js, css, images, etc.) for each UI component, and cartero will take care of ensuring that all the appropriate assets are then loaded on the pages that require them, and just those pages. Depending on a package is as simple as require( 'pork-and-beans' ). And since cartero is built on npm, the official node.js package manager, you can easily publish your packages and / or depend on other npm packages in your own code.

A package might contain assets for

  • A calendar widget
  • A popup dialog
  • A header or footer
  • An entire web page

cartero is a build tool. It does not introduce many new concepts, and the same modular organizational structure it facilitates could also be achieved by stringing together other build tools and the appropriate <script>, <link>, and <img> tags. However, using cartero is, well, a lot easier.

See this article for more info on how cartero compares to other tools, and this tutorial to get started.

Command line usage

Build all assets for a multi-page application with the cartero command. For example,

$ cartero "./views/**/index.js" "./static/assets"

This command will gather up the js and other assets required by each JavaScript entry point matching the first argument (in this case, all index.js files in the views directory), and drop the compiled assets into the output directory specified in the second argument, along with information used at run time by the hook, to load the appropriate assets for each entry point.

cartero only processes each asset one time, so compiling assets for many entry points at once is extremely efficient. Each additional entry point adds practically no overhead. cartero also separates out any JavaScript assets that are used by all your entry points into a common bundle, so that the browser cache can be leveraged to load any shared logic quickly on each page. (This magic is done by factor-bundle - thanks for your wizardry, James!)

Adding a -w flag to the cartero command will run cartero in watch mode so that the output is updated whenever assets are changed. Again, cartero's watch mode is extremely efficient, only rebuilding what is necessary for a given change.

The hook

At run time, your application needs to be able to easily figure out where assets are located. For this reason, cartero provides a small (< 100 LOC) runtime library that your server side logic can use to look up asset urls or paths based on a simple map output by cartero at build time. At the time of this writing, only a hook for node.js is available, but one can quickly be written for any server side environment.

For example, if views/page1/index.js is an entry point, the following call will return all the script and link tags needed to load the js and css bundles it requires:

h.getTagsForEntryPoint( 'views/page1/index.js', function( err, scriptTags, styleTags ) {
  // scriptTags and styleTags and strings of <script> and <link> tags, respectively.

  // attach the tags to the express res.locals so we can
  // output them in our template to load the page's assets
  res.locals.script = scriptTags;
  res.locals.style = styleTags;
} );

You can also ask the cartero hook to lookup the url of a specific asset. For example, to find the url of carnes.png in that same page1 directory.

var imageUrl = h.getAssetUrl( 'views/page1/carnes.png' );

It's all in the package.json

cartero can gather and compile style and image assets from any module with a package.json file. Just include a style and / or image property in the package.json that enumerates the assets the package requires of that type (in glob notation). For example,

{
    "name" : "my-module",
    "version" : "1.0.2",
    "main" : "lib/my-module.js",
    "dependencies" : { ... },

    "style" : "*.scss",         // styles
    "image" : [ "icon.png" ]    // images
}

Note that package.json files can be in any location. You can even put package.json files in your views folder. Sound weird? Try it. The JavaScript entry point that is used by any given view is, after all, just like a package -- it has its own js, css, and may depend on other packages (or even be depended upon). Relax your brain - does the below directory structure make sense?

├── node_modules
│   └── my-module
│       ├── index.js
│       ├── icon.png
│       ├── package.json
│       └── style.scss
└── views
    ├── page1
    │   ├── package.json
    │   ├── page1.jade        /* server side template */
    │   ├── style.css
    │   └── index.js          /* entry point for page 1 */
    └── page2
        ├── package.json
        ├── style.css
        ├── page2.jade        /* server side template */
        └── index.js          /* entry point for page 2 */

Usage

$ npm install -g cartero
$ cartero <entryPoints> <outputDir> [options]

The cartero command gathers up all assets required by the JavaScript files matching the <entryPoints> argument, which is a glob string, and transforms and concatenates them as appropriate, and saves the output in outputDir.

At run time, the HTML tags needed to load the assets required by a particular entry point can be found using the cartero hook's. The cartero express middleware can be used for an added level of convenience.

Command line options

--transform, -t         Name or path of a application level transform. (See discussion of `appTransforms` option.)

--transformDir, -d      Path of an application transform directory. (See discussion of application transforms.)

--watch, -w             Watch mode - watch for changes and update output as appropriate (for dev mode).

--postProcessor, -p     The name of a post processor module to apply to assets (e.g. uglifyify, etc.).

--maps, -m              Enable JavaScript source maps in js bundles (for dev mode).

--keepSeperate, -s      Keep css files separate, instead of concatenating them (for dev mode).

--outputDirUrl, -o      The base url of the cartero output directory (e.g. "/assets"). Defaults to "/".

--help, -h              Show this message.

Tranforms

Package specific (local) transforms

The safest and most portable way to apply transforms to a package (like Sass -> css or CoffeeScript -> js) is using the transforms key in a package's package.json file. The key should be an array of names or file paths of transform modules. For example,

{
  "name": "my-module",
  "description": "Example module.",
  "version": "1.5.0",

  "style" : "*.scss",
  "transforms" : [ "sass-css-stream" ],
  "dependencies" : {
    "sass-css-stream": "~0.0.1"
  }
}

All transform modules are called on all assets (including JavaScript files). It is up to the transform module to determine whether or not it should apply itself to a file (usually based on the file extension).

Application level transforms

You can apply transforms to all packages within an entire branch of the directory tree using the appTransforms and appTransformDirs options or their corresponding command line arguments. (Packages inside a node_modules folder located inside one of the supplied directories are not effected.) For example, to transform all sass files inside the views directory to css,

$ cartero "views/**/index.js" static/assets -t sass-css-stream -d ./views

Catalog of transforms

Any browserify JavaScript transform will work with cartero. See the parcelify documentation for a catalog of transforms that apply to other asset types.

Built-in transforms

There are three built-in transforms that cartero automatically applies to all packages.

The relative to absolute path transform (style assets only)

cartero automatically applies a transform to your style assets that replaces relative urls with absolute urls (after any local / default transforms are applied). This transform makes relative urls work even after css files are concatenated into bundles. For example, the following url reference in a third party module will work even after concatenation:

div.backdrop {
    background: url( 'pattern.png' );
}

The ##asset_url() transform (to resolve asset urls)

At times it is necessary to resolve the url of an asset at build time, for example in order to reference an image in one package from another. For this reason, cartero applies a special transform to all javascript and style assets that replaces expressions of the form ##asset_url( path ) with the url of the asset at path (after any local / default transforms are applied). The path is resolved to a file using the node resolve algorithm and then mapped to the url that file will have once in the cartero output directory. For instance, in page1/index.js:

myModule = require( 'my-module' );

$( 'img.my-module' ).attr( 'src', '##asset_url( "my-module/icon.png" )' );

The same resolution algorithm can be employed at run time (on the server side) via the cartero hook using the getAssetUrl method.

The ##resolve() transform (to resolve node-style paths to absolute paths)

Just like to the ##asset_url() transform, but evaluates to the absolute path of the referenced asset. For example, in a nunjucks template, this transform could be used to reference a template in one module from another:

{% extends "##resolve('other-module/template.nunj')" %}

{% block body %}
  ...
{% endblock %}

API

c = cartero( entryPoints, outputDir, [options] )

entryPoints is a glob pattern, or an array of glob patterns. Any JavaScript file matching the pattern(s) will be treated as an entry point. outputDir is the path of the directory into which all of your processed assets will be dropped (along with some meta data). It should be a directory that is exposed to the public so assets can be loaded using script / link tags (e.g. the static directory in express applications). Options are as follows:

  • assetTypes (default: [ 'style', 'image' ]) - The keys in package.json files that enumerate assets that should be copied to the cartero output directory.
  • assetTypesToConcatenate (default: [ 'style' ]) - A subset of assetTypes that should be concatenated into bundles. Note JavaScript files are special cased and are always both included and bundled (by browserify).
  • outputDirUrl (default: '/') - The base url of the output directory.
  • appRootDir (default: undefined) - The root directory of your application. (You generally only need to supply this option if the directory structure of the system on which your application will be run is different than of the system on which cartero is being run.)
  • appTransforms (default: undefined) - An array of transform module names / paths or functions to be applied to all packages in directories in the appTransformDirs array.
  • appTransformDirs (default: undefined) - appTransforms are applied to any packages that are within one of the directories in this array. (The recursive search is stopped on node_module directories.)
  • packageTransform (default: undefined) - A function that transforms package.json files before they are used. The function should be of the signature function( pkgJson, pkgPath ) and return the parsed, transformed package object. This feature can be used to add default values to package.json files or alter the package.json of third party modules without modifying them directly.
  • sourceMaps (default: false) - Enable js source maps (passed through to browserify).
  • watch (default: false) - Reprocess assets and bundles (and meta data) when things change.
  • postProcessors (default: []) - An array of post-procesor functions or module names / paths. Post-processors should have the same signature as transform modules. These transforms are applied to all final bundles after all other transforms have been applied. Useful for minification, uglification, etc.

A cartero object is returned, which is an event emitter.

c.on( 'done', function(){} );

Called when all assets and meta data have been written to the destination directory.

c.on( 'error', function( err ){} );

Called when an error occurs.

c.on( 'browserifyInstanceCreated', function( browserifyInstance ) );

Called when the browserify / watchify instance is created.

c.on( 'fileWritten', function( path, assetType, isBundle, watchModeUpdate ){} );

Called when an asset or bundle has been written to disk. watchModeUpdate is true iff the write is a result of a change in watch mode.

c.on( 'packageCreated', function( package ){} );

Called when a new parcelify package is created.

FAQ

Q: What is the best way to handle client side templates?

Use a browserify transform like nunjucksify or node-hbsfy to precompile templates and require them explicitly from your JavaScript files.

Q: What does cartero write to the output directory?

You generally don't need to know the anatomy of cartero's output directory, since the cartero hook serves as a wrapper for the information and assets in contains, but here is the lay of the land for the curious. Note the internals of the output directory are not part of the public API and may be subject to change.

├── static
│   └── assets                                                              /* output directory */
│       ├── 66e20e747e10ccdb653dadd2f6bf05ba01df792b                        /* entry point package directory */
│       │   ├── assets.json
│       │   ├── page1_bundle_14d030e0e64ea9a1fced71e9da118cb29caa6676.js
│       │   └── page1_bundle_da3d062d2f431a76824e044a5f153520dad4c697.css
│       ├── 880d74a4a4bec129ed8a80ca1f717fde25ce3932                        /* entry point package directory */
│       │   ├── assets.json
│       │   ├── page2_bundle_182694e4a327db0056cfead31f2396287b7d4544.css
│       │   └── page2_bundle_5066f9594b8be17fd6360e23df52ffe750206020.js
│       ├── 9d82ba90fa7a400360054671ea26bfc03a7338bf                        /* regular package directory */
│       │   └── robot.png
│       └── metaData.json
  • Each subdirectory in the output directory
    • corresponds to a particular package (some of which are entry points),
    • is named using that package's unique id,
    • contains all the assets specific to that package, and
    • has the same directory structure as the original package.
  • Directories that coorespond to entry points also contain an assets.json file, which enumerates the assets used by the entry point.
  • The metaData.json file maps package paths to package ids.

Q: Is it safe to let browsers cache asset bundles?

Yes. The name of asset bundles generated by cartero includes an shasum 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.)

Q: Will relative urls in css files break when cartero bundles them into one file?

Well, they would break, but cartero automatically applies a tranform to all your style assets that replaces relative urls with absolute urls, calculated using the outputDirUrl option. So no, they won't break.

Contributors

License

MIT

cartero's People

Contributors

a0viedo avatar butterywombat avatar colinwren avatar dgbeck avatar ferlores avatar fvntr avatar go-oleg avatar jonac22 avatar mgtitimoli avatar nico-ledesma avatar nthompson95 avatar pepoviola avatar peterkc avatar sirmatt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cartero's Issues

Error running cartero programmatically

Hi,

I'm trying to run cartero from a node script like that:

cartero = require('cartero');

res = cartero('./', './dist/', {
    assetTypes: ['files']
});

I'm getting the following error:

Error: Cannot find module './build/Release/fse' from '{userpath masked}/node_modules/cartero/node_modules/watchify/node_modules/chokidar/node_modules/fsevents'

Support for parcelsDirPath as patterns

Hey guys, I have an use case that requires that I specify a pattern of folders, due to the dynamic aspect.

Basically I have an application that mounts many different applications. Currently I could add to my cartero configuration a bunch of folders, or a folder that holds them all. But the last case it cause issues like pages that are not pages are being considered parcels and stuff like that, so its extra processing being done for no reason.

Does it make sense, based on the current architecture, to add support to something like node-glob or similar when specifying those parcelsDirPath? I could take a look into it, if it makes sense.

Support for CDN

Hey guys, I`ve been cartero for some time and I am really liking the way code is organized.

I may need to add some conditional CDN, so I think it would be cool if we could add a CDN as a dependency in the bundle.json.

Question is: is it difficult to add? I havent taken a look at the source code yet, I will do it soon, I just wanted to know u guys input regarding this.

  • When I talk about CDN support, it means to use external dependencies (just wanted to make sure it was clear)

Cartero 3: Assets.json using absolutePath

Hey guys, I am having an issue:

our deploy script basically:

  • npm install
  • grunt
  • cartero
  • move to another machine (thats the issue, due to absolutePath)
  • start

The issue is that the assets.json file maps absolutePaths.

In the previous project we used Cartero 2, there it maps only relativePath from the parcelsDir. Eg:

"header": "0e77701ef5732d1862fc323ab8a04fe11e782400",

Do you guys have any ideas why this is now the case, or if this is just a configuration issue on my part?

Question Regarding Order of Dependencies

Hey guys, I have the following structure of dependencies in my library folder. Below is just an example for discussion purposes:

app/
bootstrap/
jquery/
...

inside app/ I have my application modules, lets say:

login/
index/
header/
...
bundle.json where here I add dependencies like boostrap and jquery

In the login page, I import "app/login", but the dependencies order are as follow:

login.js
boostrap...
jquery...

Meaning, all the "app" dependencies are added below the "app/login" dependencies. Is this the correct behavior? I was thinking that, by being inside "app", any module would automatically "extend" app.

What do you guys think about this?

Problems using d3.js with cartero

Hi @dgbeck
I'm trying to use d3.js through cartero and I'm getting some errors. I believe it is because d3.js package.json is defining a browserify key here:
https://github.com/mbostock/d3/blob/master/package.json#L29

I also noticed that cartero is doing the following: https://github.com/rotundasoftware/cartero/blob/master/index.js#L225

I'm not sure about what is browserify expecting in general and if the bug is on d3.js code or in cartero. Do you mind looking at it? I'm happy to prepara a PR once we can diagnose what is the right solution
Thanks!
F

Watch=false mode causing build to not work

Hey guys just had a critical error today.

It happened TODAY, yesterday it was fine.

Basically, if I use watch = false, or not watch at all, my build process doesnt work. Browserify stops using my transforms defined as appTransforms and appTransformsDir.

I noticed that you guys upgraded cartero/parcelify, and the upgrade was to bump browserify version. I am trying to detect what caused this problem, can you guys help it out?

What if I care about the anatomy of cartero's output directory?

Is there a way to influence how cartero outputs things into the output directory? I don't like the current approach that fingerprints folders and files. Cartero is not the last step in the build process, that's why a predictive file structure matters.

How about factoring this part out into a separate module that can be plugged into cartero optionally (or switching it off via options)?

I'm only interested in concatenating and factor out common modules between different entry points and asset types...

How to reuse package assets in another package?

The following scenario:

  • core-package
    • variables.less
  • reuse-package
    • style.less

How can I re-use the LESS variables defined in variables.less from the core-package in the style.less file inside reuse-package, then transform the style.less and dump it to public/assets?

Having trouble with browserify-shim

I'm having trouble getting browserify-shim to work, even though with browserify itself I did not have an issue.

I have a package.json setup at the root, with the my browserify-shim config.

I have a parcel setup with a script that requires a "shimmed" module, but when I run cartero, I get an error that it can't find the module.

If I move the shim config into the parcel, the bundle doesn't get created at all.

Improvements: Remote Files

Hey guys, this is what I want to accomplish:

  • I want to have prodModeOnlyRemoteFiles, since I have a use case where I store a jquery dependency in a server, but I dont want to merge into my other files (join) and I dont want to have to download from the server when I am in development mode, but instead, use devModeOnlyFiles.
  • Another problem that I have is that I have multiple servers, based on environments that store remoteFiles. Meaning, I want to set "/js/jquery" as a remoteFile. The problem is that the way its implemented right now, the only difference between remoteFile and other files is that one is parsed as URL.
    -- For now, I am able to solve this problem by not managing jquery with cartero.

I didnt look into how to do the prodModeOnlyRemoteFiles, but it should be easy. But to accomplish the second improvement, I think it may require some more work. I havent analyzed this yet, so I may be wrong.

I just wanted to see if you guys have any ideas regarding this. Thanks.

Regarding v2 approach of Cartero

Hey, I have a few questions regarding this new approach that uses browserify. I dont know if its best to talk here, or if I can contact u guys.

How do u guys solve problems like:

  • I have an external dependency, like a cdn dependency. I would need to add myself the script tag, or is there a way to integrate this?
  • If i have modules that shouldnt be shared among other projects, since they are specific components of my project. How can I create this modules-like organization in this case? It looks like I can only define modules by using npm.

I thought a lot about the browserify approach, but I just cant see my projects migrating for now. Before I took a look at this cartero v2 approach, I already had started writing my own approach to cartero v1, I want something more clean and easy to extend, but not easy.

The issues with cartero v1:

  • I cant share modules. This is solved in v2, since its done by using npm. This is something that needs to be solved in my mind if I continue using v1. It could be solved by using this npm/bower approach, I will have to look into that.
  • I dont have entry points when scanning the views. So I assume all view files should be processed as they were views, and not partials/includes. This will simply slow down the transformations, specially the concat one. Note that this is solved in v2, by usage of package.json files.

Another question: you guys deprecated version 1? Internally were you guys able to replace your v1 projects to use cartero v2 with no issues?

Transforms from CLI

The transforms-flag does not appear to work. I'm more of a declarative fan when possible, so having the transforms-key in package.json is better I guess, but the flag should probably be removed to avoid confusion.

Question on fingerprint file name for bundled images

(edited after more research)

Hi @dgbeck,

I'm seeing an issue where a different image has the same fingerprint in the filename. How is the fingerprint figured out for images? Is it based on size? This might be an edge case where they are the exact same size but with different content.

Thanks

Valid assetTypes

Hello,

The docs state that using cartero API you can specify the keys in package.json that enumerate assets.

assetTypes (default: [ 'style', 'image' ]) -The keys in package.json files that enumerate assets that should be copied to the cartero output directory

To verify that it should work, I modified Example 3 of the tests contained in the cartero repo to this:

// cartero/test/example3/views/package.json
{
    "name" : "common-js",
    "main" : "common.js",
    "style" : "*.css",
    "random" : ["*.png"]
}
// cartero/test/test.js - line 119
var c = cartero( viewDirPath, outputDirPath, { assetTypes: ["random", "style"]} );

The test does not pass: not ok 12 robot.png in common package

Is there a limited set of supported keys or is it a bug?

Windows: Issue with the relative to absolute path transform (style assets only)

I followed this tutorial.

In views/index/index.js I added:

 require('../../modules/a')

In modules/a/index.css:

.a div {
    background-image: url('a.gif');
}

After running cartero, the following is produced in public/assets//index_bundle_.css:

.a div {
    background-image: url( '/e064936b0cbd0a56a284ed234f0df024e74c271eC:\a.gif' );
 }

I've assumed this is a Windows specific issue. I'm working to set up a Linux vm to confirm.

Bad Performance

Hey guys, I am currently having a performance issue, since for each page/parcel, a new browserify instance is created, and all files are processed over again.

I have a lot of coffee and jade files that are compiled. Even if I add a cache mecanism, it doesnt work, since the browserify instance changes from parcel to parcel.

Do u guys have any idea if its easy to implement a browserify instance option in cartero? I did try and for some reason I got no success, but I will still attempt this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.