Fabric.js: Allow installation via npm for browser usage

Created on 8 Feb 2016  路  52Comments  路  Source: fabricjs/fabric.js

npm has become the de-facto package manager for front end dependencies (bower is on its way out), and I would guess that most people who want to use it in a browser app nowadays try to install with npm, as I just did.

Unfortunately, the fabric.js package distributed on npm assumes that people want to use it in a node context, and has dependencies on cairo.

I don't know what the solution can be here:

  • distribute it under a different name ("fabric-frontend"?)
  • or more simply, just stop including other dependencies in the package.json, and list the requirement to cairo in the installing instructions
feature

Most helpful comment

The downside is that the build time for projects that require fabric only for browser usage is ten times longer than it needs to be, aside from the fact that it adds complexity.

All 52 comments

I do agree that it would be nice to have a backend and frontend package. However, we must make sure that the shared codebase is really shared, and not duplicated.

We could have fabric-frontend and fabric-backend modules that both rely on a fabric-core dependency. It should not take a terrible amount of time to do this, but it might take a lot of caution to make sure current dependants (on fabric) will not have their systems break down unexpectedly.

I do not agree on creating two packages. I think that who wants to install fabricjs with npm should follow instructions and install cairo libs. If for any reason installing cairo is not possible and fabricjs is required for browser only operations, they can still download it manually from website.

What is the downside of doing in this way?

The downside is that the build time for projects that require fabric only for browser usage is ten times longer than it needs to be, aside from the fact that it adds complexity.

@StephanBijzitter: You mention the possibility to split the code into "fabric-core", "fabric-frontend" and "fabric-backend"... But shipping the front-end code to backend modules would actually not be a big deal, it is very lightweight and it doesn't add any additional dependency.

So, in terms of distribution, or separation of concerns, I would mainly see:

  • a codebase common to the browser and the backend, with no additional dependency.
  • a module to ship for node environments, which would add the necessary dependencies.

The thing is, as you said, this change of distribution strategy should not break current implementations of projects that have the "fabric" package as a dependency.

So how could we move forward? I seems to me that it would be a shame to name the common module "fabric-frontend" and to reserve the name "fabric" to the node environment, as we would add a word when we remove code and dependencies.

It should ideally be the opposite:

  • "fabric" for the common / browser code.
  • "fabric-node" for the module with additional dependencies.

I don't know if this is a bad idea, but could we see this shift when a new major release is happening, and:

  • add warning messages when users run "npm install fabric", saying that the package is not anymore suited for node environments.
  • mention it in the list of the breaking changes that would come with a new major version.

What do you think?

@asturur : if fabricjs want to keep evolving, it needs to find a way to be distributed via npm for frontend projects. Neither installing huge additional dependencies nor downloading it manually can be a good future proof solution...

fabricjs will evolve with or without npm, bower and other package managers.

Said so, creating an additional package with no dependencies is not a big deal for me if @kangax agree.

I also see this option:
"The --no-optional argument will prevent optional dependencies from being installed."

So moving the dependencies as optional could be another solution.

Dividing in two different packages that complete each other is a no go, because as you see we are a very small team and we struggle keeping the issue board clear, fix bugs and keep stackoverflow's audience at peace.

I'm inclined towards publishing fabric-frontend (or fabric-no-cairo) package separately. However, I'd like to know more about what other authors do in situations like this. I imagine something like a flag or configuration option during install would be the best option.

Honestly, I see no downsides to having two packages: one with and one without Cairo.
The one with Cairo would depend on the one without Cario; so that they're always up to date with each other. As long as the codebase is not duplicated, I think it's just a matter of personal preference.

I'm definitely supporting an installation without dependencies for node.

Just to give some insight, these are the steps & problems I encountered when trying to create a custom Fabric build for a front end project (no node.js usage)

  1. Installed dependencies for Fabric, see https://github.com/Automattic/node-canvas/wiki/Installation---OSX. Got too much errors & issues which I can't grasp, since I'm not familiar with building from source.
  2. Installed & used Homebrew for installation like described here: https://www.npmjs.com/package/canvas
  3. Tried installing fabric using npm, but since Fabric 1.6.0rc1 references an outdated version of node canvas, building failed (see https://github.com/Automattic/node-canvas/issues/722)
  4. Create a npm-shrinkwrap.json file like stated in the GitHub issue
  5. Download the Fabric package without installing: npm install fabric --save-dev --ignore-scripts
  6. Once again install fabric with npm install fabric --save-dev (The shrinkwrap file now makes sure the right dependencies are used)
  7. Tried building a custom fabric build using npm build.js. This fails since files are missing in the node_modules/fabric folder (e.g. the src folder, HEADERS.js, .. aren't in the module folder since NPM ignores them using the .npmignore file)
  8. I cloned fabric's master branch into src/libs so all files are available for building (git clone https://github.com/kangax/fabric.js.git)
  9. Tried building custom fabric build using src/libs/fabric.js/build.js (this failed since uglifyjs was not installed globally)
  10. Installed UglifyJS globally: npm install uglify-js -g
  11. Build custom Fabric build: node build.js modules=interaction dest=../../js/libs/fabric.js/
  12. Success

Took me about a day to get custom fabric builds working (I'm open for improvements if there are any)

The downside of this approach is that I'm working with a git repo instead of managing my fabric-dependency in my package.json file, in which all my other dependencies are managed.

I'm not sure about the ratio of users using fabric in the browser vs. node, but I'm sure a lot of devs which simply needed a custom build for their front-end project, will use the http://fabricjs.com/build tool instead of trying to figure out how to create custom builds themselves.

If we could simplify this procedure for users which don't need the node context, I guess this will also help in clearing up some issues in the issue board & stackoverflow.

@adriaanmeuris you definitely went way overboard on that one (I'll give you some proper instructions later, I'm on my phone walking to the hairdresser right now)(try out Vagrant and run everything on a Ubuntu 14.04 box, makes it a lot easier), but fabric browser vs fabric node is probably quite equally used (although it would be cool to add metrics).

We currently use Fabric (also with custom modules) in both a browser and a node environment, but we're looking into moving away from node as the Node.js limitations are just too annoying to deal with. Instead of node, we'd use a headless browser.

Now, this is not done yet, and we're just starting to try it out... but if it does work the way we want it to, it means we still have to install a huge amount of dependencies (most of which are old and/or buggy) when we're not even going to dependent on them.

Bower is out, using npm and browserify for frontend development is gradually becoming popular. For these developers, it might be confusing & puzzling just as I have suffered. I totally agree with @vkammerer who have already come up with the best solution.

  • "fabric" for the common / browser code.
  • "fabric-node" for the module with additional dependencies.

This also makes them more cohesive.
What do you think? @asturur @kangax

You are right.
I'm new to NPM, i see there is a browser property in the package.json. What is that for?

Is possible that we are the only one with this double situation?
I bet there is a way with package.json to say "install with deps" or "install without deps"

Anyway if you install it now, and do not install node-canvas libs prerequisite, you will get some error about node canvas, but you can go on.

1.6.0 is out on npm since today.

moving dependencies in "optionalDependencies" and let the user have the option to use

npm install --no-optional fabric

Too ugly system?

That could work too.

Hello,
As i'm used to from-source and magic-happen (npm) usage, the thing that is really bothering me is that I can not use the node version that I want when coding for front end project.

For instance fabric.js install perfectly on 0.12 but fail on legacy 4.4.3 (Argon) due to some binding and node-gyp. As I'm use to that kind of issues this is not a big problem but it could become problematic when other lib ask for at least 4.x.

I've found the https://www.npmjs.com/package/fabric-browserify package that works with our stack (webpack) but update and publish on npm are not that much frequent.

In the case of fabric.js the browser field is not useful as it is only to specify specific files to be loaded (https://github.com/defunctzombie/package-browser-field-spec).
I do not see anything ugly in https://github.com/kangax/fabric.js/issues/2775#issuecomment-210533824.
First what you propose looks like the right way: https://docs.npmjs.com/files/package.json#optionaldependencies, second it is also commonly used :

Looks like we have a winner! --no-optional

fabricjs on 4.4.3 instal good. i think you have just to check node-canvas prerequisites.

Hello
so what is the solution as I am trying to use via WebPack but skip the whole nightmare of installing jsdom and canvas which is a real pain and not even needed...
tx
Sean

Like others who have commented on this issue... I am part of a large project that has 60+ UI engineers on it. I want to use Fabric for the web, and have no use-case that involve the native node stuff. I don't want to force all 60+ engineers (as well as each of our build machines) to install Cairo, and maintain it up to date.

For me... a solution where I could have a web-only fabric... that is an ideal solution. Currently, with the --no-optional flag, this doesn't not work for me. It forces me to run the install for ALL MODULES with --no-optional set, which isn't what I need. The only package that I need to do this with is Fabric.

I tried to install Fabric in the postinstall, with the --no-optional flag. That worked. However, npm, being super helpful, will try to install the optional dependencies next time I run npm install, even though the package is not listed in the package.json. So... this didn't work for me either.

This issue is closed, but seems like maybe it should still be open with several comments supporting a different approach. Something that allows a web-only install, and a separate module for native + web. To be totally honest... any solution that would allow me to accomplish my goal of not installing the native stuff, and without flipping the --no-optional flag for my entire project... seems best to me.

Edit: Nothing but love. Thanks for all the hard work to all involved with this lib. It is so powerful.

Love fabric and +1+1+1+1+1 as well!!! for targeting web only....
regards

Sean

For now... the simplest solution that I could think of (which is a solution that I hate, BTW) was to fork this repo, and then in that fork, remove the optional dependencies. Will let you know if that doesn't work. Otherwise, assume that you can fork and reproduce.

Personally I don't feel that's the right option...
regards

i m in same situation. webpack would not work with natove npm package. We are not so many engineers and when i arrived in project the solution was already taken. fabric.js file was in a folder called deps and webpack is packaging it in the vendor.js files.

So, I just tried an npm install + node build.js, but it fails because there is simply no src/ folder in the node_modules/fabric directory... why is that? What is the official and easy way of creating my own build of fabric?

website custom build or clone the repository and use blnode build.

I am running into the same problem and I am not sure what the best solution is. The flag is nice but causes problems as @aaronfrost mentioned. I'm not sure what the long-term solution is. It seems with the way that npm is structured you would have to have two repos of some sort.

In any case, a work around I found for now is using the "napa" npm package (https://www.npmjs.com/package/napa) which allows you to install something without a package.json. My package.json looks like this-

"scripts": {
    "install": "napa"
  },
"napa": {
    "fabric": "https://raw.githubusercontent.com/kangax/fabric.js/v<VERSION>/dist/fabric.min.js"
  }

It works in that I can get just the browser dependency I want in the node_modules directory and works when other members of my team do "npm install" but it is annoying to update the version in a separate place in my package.json. Also the napa package hasn't been updated recently but works. I'm sure this could be massaged into something more elegant but it at leasts get me up and running and I don't have to fork something or keep a local copy that I have to manually update in version control or something. I do hope a better solution comes about though and if I can think of something that would work better for everyone using this awesome library I will help out where I can.

Seriously though, thank you for this library it has helped me greatly on a number of projects.

I really really hope they remove the optional arguments as well

To get past this problem, I forked this repo, and in my fork, removed the optional dependencies from my package.json. That was enough to get me working again. It is a less-than-ideal solution, and something that I personally wish I didn't have to do. I wish I had time to dive in and submit a quality PR here, but... I don't. Sorry ya'll. But at least I have a "workaround" for you.

i found a canvas-prebuilt package that could solve most of the problem maybe

@aaronfrost do you keep your fork up to date on npm?
maybe we should use yours if so..

I would recommend using your own forks, and not mine. I work for a large company, and we may not be able to rev versions as fast as you need us to. So... I would recommend using your own forks. @born2net

ok tx, any special instructions that need to publish the project to npm so I can auto install as part of a build?

I just forked, and then in master removed the optional deps from the package.json. Then, in my project where I used fabric, I just added this to my package.json
image

So... as long as you have the fork, and remove the optional deps in master, it is that easy.

awesome!!! tx

I feel like this needs some serious love. It's really the only thing holding me back from using.

i want t try to switch to canvas prebuilt. tomorrow i ll let you know what happen. should be way easier to install on most of the systemd

@cgatian I am not going to lie... this lib is fantastic. The side-step I had to do was well worth all of the value of the hard work that has been put into this high-quality lib. It made my life easy. I made light work of some really complicated stuff. If your only hold up is this... I would recommend moving forward. It isn't as big of a deal as it sounds.

The only problem with that approach is that you have to keep on forking and changing every time there's a new build

i guess canvas-prebuilt works.
Webpack is a nightmare itself, it takes forever to build some apps, i do not think our jsdom and canvas will be the game changer.

I m pushing up a change with canvas prebuilt that should work easier for most of them.
Consider that the current master branch if built, gives you latest jsdom contextify free and that is easier to install on modern node version.

making a couple of changes and publishing 1.7.8 with offscreen detection and canvas-prebuilt. let me know if it works better.

preview

this is current installation, is not so bad cmon!

This issue has been "closed" for nearly two years, but is it fully resolved? What is the best way to install Fabric for front-end-only use, using NPM?

I can't understand what the two comments above mine are suggesting. Do I need to fork the repo and replace all references to canvas with canvas-prebuilt? Is this something @asturur already has put somewhere?

the issue is closed because there is no will for now to make a browser specific package.

the package.json has been modified in order to tell webpack to skip certain deps, and the node deps are all optional.

There should be a safe way to use it in webpack if properly configured. sadly i m not sure how.

+1, like @aaronfrost I also work with a large organization that has a lot of ui devs that will need this. I would rather not use fabric-webpack from npm because it hasn't been updated in...3? years. For now it seems like I'll just create a fork and remove the optional deps.

It's really quite crazy how much headache the resistance to publishing a browser only package has caused... Many other issues have since been created in this repo, that are directly related to this.

I need to check again how npm handle the node only deps and reverify that packaging should not be an issue at all.

@asturur I'm willing to help if we can call out what work is needed. My forked version pulled down fine running npm install. Pulling it into a test app right now, obviously won't be as extensive as running unit or functional testing but based on previous comments here seems like I should be fine.

Would rather not have to manage merges back into my forked branch though, and will happily provide assistance if needed.

I think here we have 2 different problems mixing togheter.
1 is that installing node-canvas is not straight forward on each server setup
2 webpack runs under node and will trigger fabricjs node switches and will require deps you do not need.

Problem number 1 is not fabric concern since fabric put the deps in optionalDependencies and failing the install should not bother the main installation. I am right with this?

Problem 2 can be probably solved at webpack configuration level. There must be a way to tell webpack to ignore some requires or to mock up a empty xldom, node-canvas and jsdom dep in the webpack setup.

In any case making a package with no deps ( that someone has to mantain ) is the shortcut, that i do not want to take here.
This problem is a common one, and should be solved in the tools, not in the packages.

Is there any webpack expert here that can partecipate in the discussion?

ok so i made this thing here:

https://travis-ci.org/fabricjs/fabricjs-webpack/

this is just an example, i took latest webpack, latest node ( to have latest npm ) and build a simple webpack bundle with fabricJS.

What i can see is that the build succedes, there are information stating that xmldom and jsdom are not bundled.

Then i test this on travis with a linux docker image where canvas can't be installed because libs are missing, npm throws warning says that an unmet optional dep is missing ( canvas ) but the intall does not fail. The build run.

So i tend toward considering this a non issue with current tools and recent fabric changes, unless someone can clearly show me a problem.

So, there's no pure front-end version of fabricjs untill now, right? As a beginner of npm, should use "npm install --no-optional fabric" to install it?

you can either link the cdn version, or putting it in your deps list, the npm will throw a warning but not stop your installation.

https://github.com/fabricjs/fabricjs-webpack

If you check the package.json of this app here, that has been put there just to show that the build pass, you will notice indeed that on modern npm ( noed 6+ ) it just works. If you are using webpack there are extra config things that you can read from that repository to have easier life.

the npm will throw a warning but not stop your installation.

If no changes are going to be made to the package to facilitate direct installation via npm, it would be great to get this information elevated to the readme installation section. It took me a while to find this issue and read all the way through to know I could ignore the npm warning.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

guettli picture guettli  路  4Comments

urcoder picture urcoder  路  5Comments

keanass picture keanass  路  5Comments

AbhijitParate picture AbhijitParate  路  3Comments

eugene-g13 picture eugene-g13  路  3Comments