• Stars
    star
    1,060
  • Rank 43,532 (Top 0.9 %)
  • Language
  • Created almost 12 years ago
  • Updated about 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

SEO for AngularJS apps made easy.

Angular-SEO

SEO for AngularJS apps made easy. Based on PhantomJS and yearofmoo's article.

Requirements

You will need PhantomJS to make this work, as it will render the application to HTML.

How to use

The solution is made of 3 parts:

  • small modification of your static HTML file
  • an AngularJS module, that you have to include and call
  • PhantomJS script

Modifying your static HTML

Just add this to your <head> to enable AJAX indexing by the crawlers.

    <meta name="fragment" content="!" />

AngularJS Module

Just include angular-seo.js and then add the seo module to you app:

angular.module('app', ['ng', 'seo']);

If you are using RequireJS, the script will detect it and auto define itself BUT you will need to have an angular shim defined, as angular-seo requires it:

requirejs.config({
    paths: {
        angular: 'http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.3/angular.min',
    },
    shim: {
        angular: {
            exports: 'angular'
        }
    }
});

Then you must call $scope.htmlReady() when you think the page is complete. This is necessary because of the async nature of AngularJS (such as with AJAX calls).

function MyCtrl($scope) {
    Items.query({}, function(items) {
        $scope.items = items;
        $scope.htmlReady();
    });
}

If you have a complicated AJAX applicaiton running, you might want to automate this proccess, and call this function on the config level.

Please that this is only a suggestion we've came up with in order to make your life easier, and might work great with some set-ups, while not working at all with others, overall, you should try it yourself and see if it's a good fit for your needs. There's alwasys the basic setup of calling $rootScope.htmlReady() from the controller.

Example:

var app = angular.module('myApp', ['angular-seo'])
.config(function($routeProvider, $httpProvider){
    $locationProvider.hashPrefix('!');
    $routeProvider.when({...});

    var $http,
            interceptor = ['$q', '$injector', function ($q, $injector) {
                var error;
                function success(response) {
                    $http = $http || $injector.get('$http');
                    var $timeout = $injector.get('$timeout');
                    var $rootScope = $injector.get('$rootScope');
                    if($http.pendingRequests.length < 1) {
                        $timeout(function(){
                            if($http.pendingRequests.length < 1){
                                $rootScope.htmlReady();
                            }
                        }, 700);//an 0.7 seconds safety interval, if there are no requests for 0.7 seconds, it means that the app is through rendering
                    }
                    return response;
                }

                function error(response) {
                    $http = $http || $injector.get('$http');

                    return $q.reject(response);
                }

                return function (promise) {
                    return promise.then(success, error);
                }
            }];

        $httpProvider.responseInterceptors.push(interceptor);

And that's all there is to do on the app side.

PhantomJS Module

For the app to be properly rendered, you will need to run the angular-seo-server.js with PhantomJS. Make sure to disable caching:

$ phantomjs --disk-cache=no angular-seo-server.js [port] [URL prefix]

URL prefix is the URL that will be prepended to the path the crawlers will try to get.

Some examples:

$ phantomjs --disk-cache=no angular-seo-server.js 8888 http://localhost:8000/myapp
$ phantomjs --disk-cache=no angular-seo-server.js 8888 file:///path/to/index.html

Testing the setup

Google and Bing replace #! (hashbang) with ?_escaped_fragment_= so http://localhost/app.html#!/route becomes http://localhost/app.html?_escaped_fragment_=/route.

So say you app is running on http://localhost:8000/index.html (works with file:// URLs too). First, run PhantomJS:

$ phantomjs --disk-cache=no angular-seo-server.js 8888 http://localhost:8000/index.html
Listening on 8888...
Press Ctrl+C to stop.

Then try with cURL:

$ curl 'http://localhost:8888/?_escaped_fragment_=/route'

You should then have a complete, rendered HTML output.

Running in behind Nginx (or other)

Of course you don't want regular users to see this, only crawlers. To detect that, just look for an _escaped_fragment_ in the query args.

For instance with Nginx:

if ($args ~ _escaped_fragment_) {
    # Proxy to PhantomJS instance here
}

githalytics.com alpha

More Repositories

1

france.code-civil

Le code civil français sous git
2,656
star
2

plugin.video.pulsar

Pulsar addon for XBMC/Kodi
Python
544
star
3

xbmctorrent

Torrent streaming for XBMC - This project has been replaced by Pulsar
Python
387
star
4

france.code-penal

Le Code pénal français, sous Git
136
star
5

dwmaxx2

Get Windows 7 windows as DirectX textures
C++
120
star
6

cross-compiler

Dockerfiles for cross compiling environments
Shell
106
star
7

python-lz4

LZ4 bindings for python
C
105
star
8

libtorrent-go

SWIG Go bindings for libtorrent-rasterbar
C++
103
star
9

torrent2http

Torrent to HTTP client for https://github.com/steeve/xbmctorrent
Go
75
star
10

itool

Single binary easy and composable iOS device interaction CLI
Go
72
star
11

france.code-procedure-penale

Le Code de procédure pénale français, sous Git
71
star
12

rupy

Python inside Ruby, the unholy alliance!
Ruby
59
star
13

docker-opencv

OpenCV on Docker
Shell
59
star
14

ToneLoc

Public non-official repository of the famous ToneLoc wardialer
C
49
star
15

pulsar

Pulsar Daemon
Go
47
star
16

script.pulsar.dummy

Dummy sample provider for Pulsar
Python
38
star
17

docker-lemp

nginx + PHP5-FPM + MariaDB + supervisord on Docker
Shell
36
star
18

aml-imgpack

Resource packer/unpacker for Amlogic Logo image files
Python
22
star
19

legifrance2json

Legifrance crawler that dumps JSON out of french legal Codes
19
star
20

ryzentosh

OpenCore Configuration for Ryzen 3950x with ASUS Crosshair VIII Hero (Wi-Fi) X570
Shell
18
star
21

msr605

Python interface for the MSR605 magnetic card reader
Python
17
star
22

dwmaxx

DWM Hacking for Windows Vista! => DEPRECATED, GO TO https://github.com/steeve/dwmaxx2
C
16
star
23

legifrance-go

Go package to manipulate legifrance dump files
Go
15
star
24

libtorrent

Mirror of libtorrent-rasterbar's SVN https://svn.code.sf.net/p/libtorrent/code/
C++
13
star
25

macos-virt

Toying around virtualising macOS for development purposes
Go
11
star
26

oculusstreetview

Fork of Oculus Street View to work with vr.js
JavaScript
11
star
27

cascading.cassandra

Cassandra Tap for Cascading!
9
star
28

seastar-rs

Experimenting with seastar and rust
Rust
8
star
29

broadcaster

Broadcast (one to many, fanout) messaging with payloads for Go
Go
7
star
30

docker-i2p

i2prouter in docker (work in progress)
Shell
3
star
31

xbmctorrent-repo

Repository for XBMCtorrent
Go
3
star
32

docker-svn2git

svn2git Docker image
2
star
33

docker-heka

Heka in a container
2
star
34

bazel_libcpp_android_issue

Python
1
star
35

steeve.github.io

My blog
HTML
1
star
36

scrapy-lxmlselector

Lxml Selector for Scrapy
1
star
37

seastar-bazel

Experiments in building a seastar app with bazel
1
star
38

quivotequoi

4tehlulz
JavaScript
1
star