paperjs / paper.js

The Swiss Army Knife of Vector Graphics Scripting – Scriptographer ported to JavaScript and the browser, using HTML5 Canvas. Created by @lehni & @puckey
http://paperjs.org
Other
14.5k stars 1.23k forks source link

NPM Install for hybrid node browser environments #739

Closed techninja closed 8 years ago

techninja commented 9 years ago

I'm making a desktop app in Electron with paper.js, and wanted to use npm to manage the package for use as a "clientside" browser component, as it does beautifully with jQuery and underscore. Using something like window.$ = window.jQuery = require('jquery'); is all that's needed in the node enabled Electron window.

Unfortunately for me, default for npm install paper includes building for node server side with Cairo, which I won't actually need.

Should I:

EDIT: I'm also open to the possibility that I simply don't know enough about the Paper.js system to say either way what I should do.

techninja commented 9 years ago

For now, I've used option 3 above and it gets me the files where I want them, which is good. It seems simply including the lib with window.paper = require('paper/dist/paper-full'); does give me the paper object, but it does not play nice, spouting the following error once a PaperScript is included on the page:

Uncaught TypeError: Cannot read property 'apply' of undefined
execute @ node_modules/paper/dist/paper-full.js:13004
(anonymous function) @ node_modules/paper/dist/paper-full.js:13039
Http.request.xhr.onreadystatechange @ node_modules/paper/dist/paper-full.js:11539
Http.request @ node_modules/paper/dist/paper-full.js:11546
loadScript @ node_modules/paper/dist/paper-full.js:13038
each @ node_modules/paper/dist/paper-full.js:133
loadAll @ node_modules/paper/dist/paper-full.js:13050

I'm supposing this has to do with node module inclusion scope restrictions (somehow), as including this file directly via <script type="text/javascript" src="node_modules/paper/dist/paper-full.js"></script> works just fine.

I'm going to move forward with this method as it works (even if it's not very "pretty"), but will keep my eyes out for any suggestions or tips if anyone has any.

lehni commented 9 years ago

We've put node-canvas into the optionalDependencies list (https://github.com/paperjs/paper.js/pull/664), so this shouldn't happen anymore?

Which version of paper are you installing?

lehni commented 9 years ago

Oh, you need to install it using:

npm install paper --no-optional
techninja commented 9 years ago

Awesome, thanks. Currently pinned to version 0.9.23 (which appears to be the latest release). I can't say this is a fully comprehensive fix, but it's certainly workable and better than --force.

I'm not entirely sure what would be needed to change in the detection logic to get var paper = require('paper') to work in Electron, or if it's even on your radar to add support for. Unfortunately it's not in my time budget to find out a solution and do a PR, and if it's not in your roadmap, then I'd say we can probably close this issue.

lehni commented 9 years ago

It'd be great to support Electron fully for sure! And I agree, it would be good to find a better fix. I am wondering if we need to offer two versions of paper on NPM, one for Node.js environments and one for people working with the browser.

techninja commented 9 years ago

Oh, sweet, glad it's on your radar! Whatever method you choose, be sure to include support for the nw.js guys. They're method is similar to Electron, and allows both DOM and Node.js API/require access in the browser.

lehni commented 9 years ago

Gee, way too many ways of packaging and loading things out there. Keeping it all on the radar could be a full time job in itself :)

lehni commented 9 years ago

So the problem is that we have two basic versions of paper.js, one for browsers and one for the headless node.js environment. The issue with electron is that it is both, and based on your use-case, you'll want one or the other. This describes the complexities that we're facing pretty well:

https://github.com/atom/electron/issues/1574

I'm not sure yet what a good solution will look like.

techninja commented 9 years ago

I think Paul on that issue said it best:

...what you want depends on what you're doing.

If we know the two supported use cases...

  1. Node side render/path management
  2. DOM Access & canvas management clientside library)

...then we can likely choose the best path for release.

For my project, I just wanted to use the same module & version management tools as node, but restrict use in my application to "clientside" only, meaning the build portion of npm install will fail as it assumes the first use case.

Perhaps modern JS libraries need to outline their use cases for the now three (node, browser, & hybrid) environments, and then only support those. I'd imagine as these things get more common, NPM will instate some kind of third category defining the hybrid environment (next to main & browser).

In this hypothetical situation, this project would define the node only main to the node only project, and both the browser and hybrid to the same clientside library. And as soon as you support a third use case you can change that to a new JS file designed with both in mind. Of course there's likely other changes needed to both the library to recognize the slight differences of a browser vs a hybrid system.

Of course none of this gets us anywhere fast unless people much further up the rungs of the ladder agree on such a thing. In the mean time, it may simply behoove this issue to discuss simpler things like providing a node only module that then requires the central library which is also the clientside/hybrid compatible library.... ?

I can't say I've done my homework to know enough about what it takes to build these or the differences between them. I may be totally off base, but I can certainly hope I've at least lended an idea int he right direction.

oveddan commented 8 years ago

+1

lehni commented 8 years ago

I think it boils down to this:

We should move away from the separate builds for browser and server, and create one hybrid build, or two, as we probably still want to provide paper-core.js and paper-full.js, to provide a smaller version for people who don't use PaperScript. We can keep using prepro.js to build these, but have far less branching in the preprocessing instructions.

The node.js version then can require a separate file that adds some node.js specific dependencies and work-arounds, along with this hybrid version.This would then also simplify the work on a web-worker friendly version (#634).

oveddan commented 8 years ago

Agreed @lehni - in recent years, there has been a big shift towards browser based applications built using webpack or browserify, which handle modularization of code and prevent polluting the global namespace, and those of us who use those tool wouldn't feel the need to really use paperscript, when we can do something like:

import paper, { view, Path, Group, Point } from 'paper'

paper.setup(domNode)
path = new Path(params)

view.onFrame = function({
})
lehni commented 8 years ago

That's not really what PaperScript is about. The main benefit is the addition of operator overloading and its use in the Point class, to simplify teaching of vector graphics and geometry.

lehni commented 8 years ago

Related: #582

Pomax commented 8 years ago

As an external user's contribution on the "paper-core vs. paper-full" concept, the size difference is essentially irrelevant (core is already 338kb, so if that's an acceptable payload, the extra 50kb is not going to matter either. And minified the difference is 187kb vs. only 30kb more, again that's not a big enough difference), and the memory footprint difference gets lost in the much more massive overhead of the browser itself. Maintaining a core vs full distinction is probably far less important than separating into "the bulk of the library that does the work" and "the part of the library that does the actual drawing of things using some object with a canvas-compatible API".

lehni commented 8 years ago

That's certainly worth a thought. But according to that logic, I would then much rather not do any separating at all. : )

Pomax commented 8 years ago

@oveddan ah, but you still want paperscript, because writing a Webpack paperscript-loader that preprocesses any .ps files so that they get transformed to "regular" JS before getting passed into the build is (not trivial but) entirely doable. In fact, I'd love me one of those.

@lehni "that logic" being "separate the processing from the actual draw instructions"? Because I agree: you'd need very little separation. As long as a Paper.setup(canvasAPIequivalentObject) is available, and the library doesn't refuse to work if none is bound (just don't draw), that would be enough to make things work both in the browser, as well as in Node or any other "I don't have a canvas but I have XYZ" context. The one thing that might be worth splitting on is the parser vs. the library, so that it's possible to get the conversion result from paperscript to plain JS (so it can be used for preprocessing offline/serverside/whateverFadNameItHasToday) in a webworker, separate thread, etc.

lehni commented 8 years ago

No I meant the logic that 30kb more isn't a big deal. I haven't measured it but the code that does the drawing is much smaller than that, so I don't think it's worth splitting off either... I'll be working on supporting paper scopes without a view (or with a DummyView) for sure, since that's required for web workers as well.

And there's already an issue for the separate parser: #656

Pomax commented 8 years ago

ahh, yeah that makes sense. I have nothing more to add it seems =D

lehni commented 8 years ago

So I have started working on the transition to this unified version. First step: Make jsdom's Image object function like the browser's: https://github.com/tmpvar/jsdom/issues/1365 / https://github.com/tmpvar/jsdom/pull/1366

lehni commented 8 years ago

So since e1a51f858ad78a9b1a9daf289d98c33ee1ce6101, this is starting to look very good. The only issue is that it requires a modified version of jsdom. I currently use it with https://github.com/lehni/jsdom/tree/paper.js, which is v7.2.2 with my work on Image / Canvas support patched in from upstream. It seems to work well, but more testing is needed.

lehni commented 8 years ago

I've merged this into develop now. Closing.

Pomax commented 8 years ago

\o/

pajtai commented 5 years ago

Agreed @lehni - in recent years, there has been a big shift towards browser based applications built using webpack or browserify, which handle modularization of code and prevent polluting the global namespace, and those of us who use those tool wouldn't feel the need to really use paperscript, when we can do something like:

import paper, { view, Path, Group, Point } from 'paper'

paper.setup(domNode)
path = new Path(params)

view.onFrame = function({
})

@oveddan is that how you use Paper with npm / webpack? It'd be great if that was included in the examples. All the example use attributes on script tags, which isn't always convenient.