I have a project using Spring MVC + AngularJS. All the data is dynamic. Have some big database of locations in this app.
For SEO purposes, need to generate a static page for each location and put them on SEO-friendly URLs (ex. /localhost/path1/path2/here-is-very-friendly-name)
What is the best way to make it?
Should i just generate a pages separately and put them to some separate folder from the main app (if it is, whats the best way to make it?), or i can use Spring/Angular for that?
(for additional info)
each location's object contains id
,name
, latitude
, longtitude
, address
, district
, city
, country
.
Actually it's my Angular/SEO experience.
You have to made lots of changes!!
1) Removing #
from url
app.config(['$locationProvider', function ($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}]);
2) Review your MVC Routing
Till now maybe you had one HomeController for returning index.cshtml
and booting up your Angular App.
After removing #
from Angular routing, you have to set MapRoute
for all of your routes.
Because in this situation the first time you try to visit routes like www.site.com/any_route
Angular App not loaded yet so it tries to get page from MVC Routing. But after that $routeProvider
do its duties.
3) Use MVC variables for meta tags
For better indexing and being friend with crawlers and bots we have to use MVC variables for initializing website meta tags.
If you set your page title by Angular bindings like <title>{{title}}</title>
whenever you want to share your page through social networks you will see {{title}}
because social networks can't render sites.
<title>@ViewBag.title</title>
<meta name="Description" content="@ViewBag.description">
<meta name="Keywords" content="@ViewBag.keywords">
<meta property="og:title" content="@ViewBag.title" />
<meta property="og:description" content="@ViewBag.description" />
4) Replace Angular binding for meta tags
Our app is SPA, so after loading Angular we are out of MVC playground. We have to replace Angular variables with MVC variables.
angular.element('title').remove();
angular.element('meta[name="Description"]').remove();
angular.element('meta[name="Keywords"]').remove();
angular.element('meta[property="og:title"]').remove();
angular.element('meta[property="og:description"]').remove();
var description = angular.element('<meta name="Description" content="{{meta.description}}">');
angular.element('head').prepend(description);
var keyword = angular.element('<meta name="Keywords" content="{{meta.keywords}}">');
angular.element('head').prepend(keyword);
var titleOg = angular.element('<meta property="og:title" content="{{meta.title}}" />');
angular.element('head').prepend(titleOg);
var descriptionOg = angular.element('<meta property="og:description" content="{{meta.description}}" />');
angular.element('head').prepend(descriptionOg);
var title = angular.element('<title ng-bind="meta.title"></title>');
angular.element('head').prepend(title);
$rootScope.$applyAsync(function () {
$compile(title)($rootScope);
$compile(description)($rootScope);
$compile(keyword)($rootScope);
$compile(titleOg)($rootScope);
$compile(descriptionOg)($rootScope);
});
5) use JSON-lD
for dynamic contents
If you are familiar with SCHEMA.org you better to use JSON-LD
instead of others, because search engines bots can catch and analyse <script type="application/ld+json"></script>
s that inserted dynamically after page loaded.
You have to check Schema Dictionary
to find the type that is most closer to your data structure.
For example it's my company json-ld:
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@type" : "Organization",
"name" : "داده کاوان امیرکبیر",
"alternateName" : "ADM | Amirkabir Data Miners",
"description": "شرکت داده کاوان امیرکبیر | تولید کننده نرم افزارهای تحت وب، از قبیل حسابداری آنلاین 'کاج سیستم' ، سیستم مدیریت پروژه 'تسک من' و ...",
"url" : "https://adm-co.net",
"email": "[email protected]",
"logo": {
"@type": "ImageObject",
"url": "http://khoonamon.com/images/ADM_Logo.png",
"caption": "لوگو داده کاوان امیرکبیر",
"width": "2480px",
"height": "1459px"
},
"telephone": "+98-21-44002963",
"address": "تهران، خیابان آیت ا... کاشانی، نبش خیابان عقیل، پلاک 380، طبقه دوم",
"contactPoint" : [{
"@type" : "ContactPoint",
"telephone" : "+98-21-44002963",
"contactType" : "customer service",
"contactOption" : "TollFree",
"areaServed" : "IR",
"availableLanguage" : "Persian"
}],
"sameAs" : [
"https://google.com/+ADMcoNet-GPlus",
"https://www.linkedin.com/company/adm-amirkabir-data-miners-?trk=biz-companies-cym",
"https://instagram.com/AmirkabirDataMiners/",
"https://www.facebook.com/AmirkabirDataMiners",
"http://www.pinterest.com/AmirkabirDM/",
"https://twitter.com/AmirkabirDM",
"https://www.youtube.com/channel/UCQxP0vZA05Pl9GlyXXQt14A/about"
]
}
</script>
Have you tried tools like SEO.js (http://getseojs.com/) and prerender.io (https://prerender.io/). Have you tried those?
I haven't tried it myself but PhantomJs would likely be the best option to be able to do this.
You'll need a dictionary of the endpoints your want to render and their corresponding static filepath names. You'd then iterate over each endpoint, rendering the given path with PhantomJS and then saving the output into the static file.
From what I gather from your question, you haven't actually used these paths on the front-end in your angular app as yet? If this is the case then I'd say that the other option is to actually render them server side via just Spring.
The issue here is that angular is not made with isomorphism (client and server side rendering) in mind. Any proper rendering you want done on the server side that hasn't been built yet, the best option is to use Spring to render it.
Another option is updating to Angular2 which is isomorphic with the help of angular universal. If Spring is not used for rendering and only serves as an API for your app this option will work well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With