SEO angulaire en action:


Ce référentiel est maintenu par Trilon.io et l'équipe universelle angulaire et est censé être un démarreur avancé pour ASP.NET Core 2.1 en utilisant Angular 7.0+, non seulement pour le côté client, mais à être rendu sur le serveur pour les peintures d'application instantanées (note: si vous n'avez pas besoin de SSR, mais lisez ici comment le désactiver).
Ceci est censé être une application de démarrage riche en fonctionnalités contenant toutes les dernières technologies, les meilleurs systèmes de construction disponibles et incluent de nombreux exemples et bibliothèques du monde réel nécessaires dans les applications (SPAS) (SPAS).
Cela utilise toutes les dernières normes, pas de gorgée, pas de bower, pas de dactylographies, pas de "construire" manuellement rien. NPM, WebPack et .NET gèrent tout pour vous!
Ce ne sont que quelques-unes des fonctionnalités trouvées dans ce démarreur!
ASP.NET 2.1 - VS2017 Prise en charge maintenant!
Angular 7.0.0 :
ng gc components/example-componentng gs shared/some-serviceWebPack Build System (WebPack 4)
Test des cadres
Productivité
ASP.net Core 2.1
Azuré
npm i -S @markpieszak/ng-application-insights en tant que dépendances. // Add the Module to your imports
ApplicationInsightsModule . forRoot ( {
instrumentationKey : 'Your-Application-Insights-instrumentationKey'
} )Docker
Assurez-vous que .NET Core 2.1 Installé et / ou VS2017 15.3. VS2017 installera automatiquement toutes les dépendances NPM et .NET NECCECSSARY lorsque vous ouvrez le projet.
Poussez simplement F5 pour commencer le débogage!
Docker-Support : modifiez le projet de démarrage en docker-compose et appuyez sur F5
Remarque : Si vous obtenez des erreurs après cela, telles que module not found: boot.server (ou similaire), ouvrez la ligne de commande et exécutez npm run build:dev pour vous assurer que tous les actifs ont été correctement construits par WebPack.
Remarque: Assurez-vous que le débogueur C # Extension et .NET Core a été installé.
Le projet est livré avec les fichiers Launch.json configurés pour vous permettre de pousser F5 pour démarrer le projet.
# cd into the directory you cloned the project into
npm install && npm run build:dev && dotnet restore
# or yarn install Si vous exécutez le projet à partir de la ligne de commande avec dotnet run assurez-vous de définir vos variables d'environnement sur le développement (sinon des choses comme HMR pourraient ne pas fonctionner).
# on Windows:
set ASPNETCORE_ENVIRONMENT=Development
# on Mac/Linux
export ASPNETCORE_ENVIRONMENT=Development Utilisation dotnet publish , quand il est terminé, placez le dossier généré sur votre serveur et utilisez IIS pour tout tirer.
git remote add azure https://[email protected]:443/my-angular2-site.git
// ^ get this from Azure (Web App Overview section - Git clone url)
git push --set-upstream azure master Remarque: Cette application a une configuration WebAPI (notre API REST) dans le même projet, mais bien sûr, tout cela pourrait être abstrait en un out des projets complètement séparés. .NET Core Things est tous réalisé dans le même projet pour la simplicité.
Fichiers de niveau racine
Ici, nous avons les suspects habituels trouvés au niveau racine.
Fichiers orientés vers l'avant:
package.json - Dépendances et scripts du projet NPM.tsconfig - Configuration de type TypeScript (ici nous configurons également des chemins)webpack - Fichiers de configuration (regroupement modulaire + tellement plus)karma - Fichiers de configuration (test unitaire)protractor - Files de configuration (test E2E)tslint - Règles de liaison de code TypeScriptVoyons comment cela est structuré afin que nous puissions comprendre tout cela!
Avec Angular Universal, nous devons diviser notre logique d'application par plate-forme , donc si nous regardons à l'intérieur de ce dossier, vous verrez les 2 fichiers racine, qui branchent la logique entière pour le navigateur et le serveur respectivement.
Ici, nous configurons quelques éléments, le client Angular Bootstrap.
Vous aurez à peine besoin de toucher ce fichier, mais quelque chose à noter, c'est le fichier où vous importeriez des bibliothèques que vous voulez uniquement être utilisées dans le navigateur. (Sachez simplement que vous devrez fournir une simulation d'implémentation pour le serveur lorsque vous le faites).
Remarquez la structure du dossier ici dans ./ClientApp/ :
+ /ClientApp/
+ /app/
App NgModule - our Root NgModule (you'll insert Components/etc here most often)
AppComponent / App Routes / global css styles
* Notice that we have 2 dividing NgModules:
app.module.browser & app.module.server
You'll almost always be using the common app.module, but these 2 are used to split up platform logic
for situations where you need to use Dependency Injection / etc, between platforms.
Note: You could use whatever folder conventions you'd like, I prefer to split up things in terms of whether they are re-usable
"components" or routeable / page-like components that group together and organize entire sections.
+ + > ++ > /components/
Here are all the regular Components that aren't "Pages" or container Components
+ + > ++ > /containers/
These are the routeable or "Page / Container" Components, sometimes known as "Dumb" Components
+ + > ++ > /shared/
Here we put all shared Services / Directives / Pipes etc Lorsque vous ajoutez de nouvelles fonctionnalités / composants / etc. à votre application, vous ajouterez généralement des choses à la racine ngmodule (située dans /ClientApp/app/app.module.ts ), mais pourquoi y a-t-il deux autres ngmodules dans ce dossier?
En effet, nous voulons diviser notre logique par plate-forme , mais notez qu'ils partagent tous deux le Ngmodule commun nommé app.module.ts . Lorsque app.module.browser || app.module.server ajoutez la plupart des choses à votre application, c'est le seul endroit où vous devrez ajouter votre nouveau composant / directif / tuyau / etc. app.module.browser || app.module.server .
Pour illustrer ce point avec un exemple, vous pouvez voir comment nous utilisons l'injection de dépendance pour injecter un StorageService différent pour le navigateur et le serveur.
// For the Browser (app.module.browser)
{ provide : StorageService , useClass : BrowserStorage }
// For the Server (app.module.server)
{ provide : StorageService , useClass : ServerStorage }N'oubliez pas que vous n'aurez généralement qu'à vous soucier de
app.module.ts, car c'est là que vous ajouterez la plupart de vos applications de nouveaux aspects!
Comme nous l'avons souligné, ceux-ci sont là pour des simplicités, et de manière réaliste, vous pouvez vouloir des projets séparés pour tous vos microservices / projets API REST / etc.
Nous utilisons MVC dans cette application, mais nous n'avons besoin que d'un seul contrôleur, nommé HomeController . C'est là que toute notre application angulaire est sérialisée en une chaîne, envoyée au navigateur, ainsi que tous les actifs dont il a besoin pour ensuite bootstrap sur le côté client, et devenir un spa à part entière par la suite.
La version courte est que nous invoquons ce processus de nœud, transmettant notre objet de demande et invoquons le fichier boot.server , et nous récupérons un bel objet que nous passons dans l'objet .nets ViewData , et saupoudons dans nos Views/Shared/_Layout.cshtml et /Views/Home/index.cshtml !
Une explication plus détaillée peut être trouvée ici: NG-ASPNETCORE-MENNINE README
// Prerender / Serialize application
var prerenderResult = await Prerenderer . RenderToString (
/* all of our parameters / options / boot.server file / customData object goes here */
) ;
ViewData [ "SpaHtml" ] = prerenderResult . Html ;
ViewData [ "Title" ] = prerenderResult . Globals [ "title" ] ;
ViewData [ "Styles" ] = prerenderResult . Globals [ "styles" ] ;
ViewData [ "Meta" ] = prerenderResult . Globals [ "meta" ] ;
ViewData [ "Links" ] = prerenderResult . Globals [ "links" ] ;
return View ( ) ; // let's render the MVC View Jetez un œil au fichier _Layout.cshtml par exemple, remarquez comment nous laissons .net gérer et injecter toute notre magie de référencement (que nous avons extrait d'Angular lui-même)!
<!DOCTYPE html >
< html >
< head >
< base href =" / " />
<!-- Title will be the one you set in your Angular application -->
< title > @ViewData["Title"] - AspNET.Core Angular 7.0.0 (+) starter </ title >
< meta charset =" utf-8 " />
< meta name =" viewport " content =" width=device-width, initial-scale=1.0 " />
@Html.Raw(ViewData["Meta"]) <!-- <meta /> tags -->
@Html.Raw(ViewData["Links"]) <!-- <link /> tags -->
< link rel =" stylesheet " href =" ~/dist/vendor.css " asp-append-version =" true " />
@Html.Raw(ViewData["Styles"]) <!-- <style /> tags -->
</ head >
... etc ... Nos Views/Home/index.cshtml rendent simplement l'application et sert les fichiers webpack groupés.
@Html.Raw(ViewData["SpaHtml"])
< script src =" ~/dist/vendor.js " asp-append-version =" true " > </ script >
@section scripts {
< script src =" ~/dist/main-client.js " asp-append-version =" true " > </ script >
}Eh bien maintenant, votre angulaire côté client prendra le relais et vous aurez un spa entièrement fonctionnel. (Mais nous avons gagné tous ces grands avantages SEO d'être rendu de serveurs)!
Lors de la construction de composants dans Angular 7, il y a quelques choses à garder à l'esprit.
Assurez-vous de fournir des URL absolues lorsque vous appelez des API. (Le serveur ne comprend pas les chemins relatifs, donc /api/whatever échouera).
Les appels API seront effectués pendant un serveur, et encore une fois pendant le rendu du client, assurez-vous donc d'utiliser le transfert de données qui vous est importante afin que vous ne voyiez pas de scintillement.
window , document , navigator et autres types de navigateur - n'existent pas sur le serveur - donc les utiliser, ou toute bibliothèque qui les utilise (jQuery par exemple) ne fonctionnera pas. Vous avez des options, si vous avez vraiment besoin de cette fonctionnalité:
import { PLATFORM_ID } from '@angular/core' ;
import { isPlatformBrowser , isPlatformServer } from '@angular/common' ;
constructor ( @ Inject ( PLATFORM_ID ) private platformId : Object ) { ... }
ngOnInit ( ) {
if ( isPlatformBrowser ( this . platformId ) ) {
// Client only code.
...
}
if ( isPlatformServer ( this . platformId ) ) {
// Server only code.
...
}
}setTimeout . Il ralentira le processus de rendu côté serveur. Assurez-vous de les ngOnDestroy dans les composants.Ne manipulez pas directement l'élément indigène . Utilisez le rendu2 . Nous le faisons pour garantir que dans tout environnement, nous pouvons changer notre point de vue.
constructor ( element : ElementRef , renderer : Renderer2 ) {
this . renderer . setStyle ( element . nativeElement , 'font-size' , 'x-large' ) ;
}sass-loader nécessite node-sass > = 4: soit dans le conteneur Docker ou LocalHost Run NPM Rebuild Node-Sass -F Commentez simplement la logique dans HomeController et remplacez @Html.Raw(ViewData["SpaHtml"]) avec uniquement votre applications Root AppComponent TAG ("App-Root" dans notre cas): <app-root></app-root> .
Vous pouvez également supprimer n'importe quelle logique
isPlatformBrowser/etcet supprimer les fichiers boot.server, app.module.browser & app.module.server, assurez-vous simplement que votre fichierboot.browserpointe versapp.module.
Vérifiez les Gotchas sur la façon d'utiliser isPlatformBrowser() .
Vous voudrez soit supprimer le SSR pour l'instant, soit attendre car le support devrait venir pour gérer le rendu de serveur de plate-forme. Cela est maintenant possible, avec les changements de matériel angulaire récemment mis à jour. Nous n'avons pas encore de tutoriel disponible pour cela.
Remarque: si possible, essayez d'éviter d'utiliser jQuery ou de bibliothèques en fonction, car il existe de meilleures façons plus abstraites de gérer le DOM en angulaire (5+) comme l'utilisation du rendu, etc.
Oui, bien sûr, mais il y a quelques choses que vous devez configurer avant de le faire. Tout d'abord, assurez-vous que jQuery est inclus dans le fichier de fournisseur WebPack et que vous avez une configuration de plugin WebPack pour cela. new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' })
Maintenant, assurez-vous que tous les "plugins", etc. que vous avez, ne sont inclus que dans votre fichier boot.browser.ts . (IE: import 'slick-carousel'; ) Dans un composant que vous souhaitez utiliser jQuery, assurez-vous de l'importer près du sommet comme tel:
import * as $ from 'jquery' ; Assurez-vous toujours d'envelopper tout ce qui a orienté jQuery dans le conditionnel d' isPlatformBrowser() d'Angular!
Pour prendre en charge IE9 via IE11, ouvrez le fichier polyfills.ts dans le dossier polyfills et décommentez les «polyfills d'importation» au besoin. Assurez-vous également que votre webpack.config et webpack.config.vendor changent l'option de TerserPlugin de ecma: 6 à ecma: 5 .
Merci beaucoup à Steve Sanderson (@Stevesandersonms) de Microsoft et à son travail incroyable sur JavascriptServices et à l'intégration du monde du nœud avec ASP.net Core.
Merci également aux nombreux contributeurs!
Consultez nos problèmes plus faciles ici
Rien n'est jamais parfait, mais faites-le moi savoir en créant un problème (assurez-vous qu'il n'y en a pas déjà un existant), et nous essaierons de déterminer un correctif! Si vous avez de bonnes idées ou si vous souhaitez contribuer, n'hésitez pas à faire un problème avec la proposition, ou simplement à faire un RP à partir de votre fourchette.
Copyright (c) 2016-2019 Mark Pieszak
Consultez Trilon.io pour plus d'informations! Twitter @trilon_io
Contactez-nous à [email protected] et parlons de vos besoins de projets.
Twitter: @trilon_io