saymedia / angularjs-server

Specialized server for AngularJS sites
MIT License
248 stars 49 forks source link

Hard to use angular from npm? #24

Closed randallb closed 9 years ago

randallb commented 9 years ago

In my serverScripts i have:

serverScripts: [dirname + "/../node-modules/angular/angular.js", dirname + '/permalink-app.js']

Which are the proper paths. I get this error:

TypeError: Cannot read property 'module' of undefined
  at Object.module (/Users/rb/Dropbox/ac/netshow/www/node_modules/angularjs-server/node_modules/angularcontext/lib/main.js:146:38)

I'm trying to use Angular from NPM (1.3.whatever). Is this unsupported for some reason? Does my angular version need to be 1.2?

My next step is to download angular and try to use it directly to see what happens.

randallb commented 9 years ago

I might have screwed something up. waiting till i'm sure it's good.

apparentlymart commented 9 years ago

Okay... feel free to open another issue if you find that there really is a bug.

By the way, rather than directly specifying the path to the angular module, you might prefer to use require.resolve to let node itself tell you where to find the angular module.

randallb commented 9 years ago

I had a really hard time getting this up. We use browserify, and I kept getting "not found" errors that didn't have a stack trace, or tell me what they couldn't find.

What does the "not found" error mean?

apparentlymart commented 9 years ago

Here's an example of using AngularJS-server with browserify: https://gist.github.com/apparentlymart/6679a9d9d4f4cbdefa1f

With that said, I think the "Not Found" error you are seeing is what the built-in htmlGenerator middleware returns when it can't find a route matching the request URL. That particular middleware is making a bunch of assumptions for quick setup in simple cases. Most notably:

If either of these things are not true for your application, you can build your own "HTML generator" using the lower-level primitives. This is in fact what we do within our main app at Say Media, since that app has its own custom router that does all of the routing work on the server.

The makeHtmlGenerator function in lib/main.js shows how the built-in implementation works. As shown in the main readme, you can make your own middleware that has access to the AngularJS context using wrapMiddlewareWithAngular:

app.use(
    angularMiddlewares.wrapMiddlewareWithAngular(
        function (req, res, next, injector) {
            var $rootScope = injector.get('$rootScope');
            var $interpolate = injector.get('$interpolate');
            $rootScope.name = 'world';
            var greeting = $interpolate('Hello, {{name}}')($rootScope);
            res.end(greeting);
        }
    )
);

That is a very basic example, but you have access to the whole AngularJS API and any additional apps you've loaded from that injector object, so in principle you can e.g. interact with the ui-router if that's what your app is using. The wrapMiddlewareWithAngular function, as well as providing that injector object, also ensures that the $location service in that context is populated with the relevant data from the req object, so any router building on $location should be able to work as (close to) normal.

AngularJS-server is not able to provide a "perfect" browser-like environment to run your application in, so you should expect that some amount of tweaking will be required to make it work, depending on how far your application is from the assumptions of the built-in utility functions. AngularJS-server is a utility to help you port your AngularJS app to the server, not a drop-in solution for server-side rendering.

randallb commented 9 years ago

So I'd recommend making this the default setup. It's much simpler to understand and configure than the "normal" setup. I got this going within 5 minutes.

Maybe once you get that going, layer on routing and stuff gradually in the example.

randallb commented 9 years ago

Also it'd be great if I knew what this was trying to do on the server... specifically what "window-like" stuff is this trying to emulate? Is it building a full jsdom thing?

randallb commented 9 years ago

Also are the "clientscripts" injected via script tag or directly?

randallb commented 9 years ago

Lastly, is it possible to provide raw js for the serverscripts configuration option rather than a file path? Our stuff uses browserify, but uses it as middleware (for now). So I don't have a real file path yet per se. Trying to figure out how best to deal with that.

randallb commented 9 years ago

I'm guessing on my last question it'll just be up to me to do that in the lower level injector thingy. Working on it now.

kshay commented 9 years ago

Yes, you can supply a mixture of raw JS and paths, although I'm not finding that documented anywhere except in this comment in the underlying angularcontext module:

https://github.com/apparentlymart/node-angularcontext/blob/master/lib/main.js#L29

randallb commented 9 years ago

So i tried to do that but still failed. I even tried angularcontext on its own and that was a fail. I couldn't figure out how to let it know it wasn't a file btu instead was a js string. :/

kshay commented 9 years ago

Sorry, I should have been more explicit... instead of a string, you use an array of [JS string, arbitrary "filename" for debugging]. So your serverScripts might look like:

[
    '/some/where.js',
    ['console.log("foo");', 'myLogCode.js'],
    '/else/where.js'
]