Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

browserify compatibility should allow code to be run server-side #11449

Closed
boneskull opened this issue Mar 27, 2015 · 6 comments
Closed

browserify compatibility should allow code to be run server-side #11449

boneskull opened this issue Mar 27, 2015 · 6 comments

Comments

@boneskull
Copy link
Contributor

Thanks everyone for #10732 and especially @linclark for documenting it.

I don't know why anyone would want to run their AngularJS application or library on the server, but running tests headlessly in that context is very convenient.

For anyone interested who wishes to test AngularJS code via NodeJS (say via Mocha or something), you'll need the jsdom module, with some sort of fixture such as this in your spec file(s):

// AngularJS needs document and window globals to run
global.document = require('jsdom').jsdom('<html><head></head><body></body></html>');
global.window = global.document.parentWindow;

// because AngularJS' index.js expects angular to be in the global namespace, 
// we need to fake it a bit.
// we make this an object so we can easily extend it with the real angular object below
global.angular = {};

// returns the empty object above
var angular = require('angular');

// extend the local angular object with the contents of global.window.angular, 
// which is the real angular object.
global.window.angular.extend(angular, global.window.angular);

I'd be interested if we could somehow avoid this boilerplate by modifying index.js. Adding jsdom as an npm dependency may not be feasible (angular-mocks might want to do this, however--I'd like to hear opinions on that), but perhaps index.js could detect the presence of global.window and global.document and instead export global.window.angular?

@monokrome
Copy link

To provide some more reasoning for this, Angular is really close to being able to render directives and such on the server side.

In terms of providing good user experiences, some people want to render the initial page that a user sees on the server and let the front-end framework take over on top of the server-baked content using the same codebase. Although it is possible to get this working, the biggest issue seems to me to be that Angular depends on a global window variable.

It'd be useful if this wasn't the case, because it essentially means that we need to wrap Angular in a factory for each request in order to get a separate JSDOM window for each URL / request. If you don't do this then the $window service provides potentially unexpected behavior when used on the client vs the server.

Browserify is a bit of a hack, and it'd be nice to see Angular consider support for server usage without needing to wrap it in the first place.

In my opinion, the problem here is that Angular depends on a global window variable. A possibly decent solution could be to allow an optional window argument to angular.bootstrap that allows bootstrapping against multiple window instances (and ideally supporting a null case). Once you have given a window to Angular, it works pretty well aside from HTTP requests - but I think this issue seems like the big blocker.

The document variable isn't required to be global as long as you are manually bootstrapping, and I think that this may be the right way to go on the server anyway.

Not sure if Angular is interested in being a framework for server-side rendering, but I feel like it's a pretty good goal to have.

@petebacondarwin
Copy link
Contributor

We are not going to support this in Angular 1 (but Angular 2 maybe...)

@monokrome
Copy link

@petebacondarwin Any insight regarding why? Seems like a small enough change that disregarding without providing reasoning is a bit scary when the other option is to wait for an unreleased product to only possibly support it in the future.

@petebacondarwin
Copy link
Contributor

@monokrome - sorry for my short reply. It was a busy day.

To give a bit more context:

When we talk about server side rendering we ought to be clear what we expect. What most people think about is the idea of downloading to the browser a frozen snapshot of the Angular application that is somehow restarted as a normal Angular app once it arrives; the aim here is to provide a faster initial experience for the user when first accessing a page.

The Angular team did actual spend a period of time in 2013/14 trying to implement this kind of server side rendering. Simply rendering the directives on the server is not enough. We must also be able to describe to the unfrozen application exactly what directives were running and what state they expect to be in when the application restarts. Simply exposing the window object to allow the server to mock it is not enough.

They did get it working in a prototype but it was a bit hacky and was not a clean solution. In the end the team turned its attention to the complete rewrite for Angular 2, which is much better architected for supporting something like server-side rendering.

@monokrome
Copy link

Thanks a ton for following up, @petebacondarwin. I got this working in a prototype in a couple hours, but I guess there were probably some edge cases that were found? I'm wondering if those are documented anywhere if so

@boneskull
Copy link
Contributor Author

FWIW server-side rendering is not the use case I originally described in the ticket. @petebacondarwin Please don't confuse my request with that--I'm just asking for potentially some sort of stub or assistance in reducing the boilerplate necessarily to heedlessly test AngularJS apps.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants